Button
Interactive element that triggers actions when clicked.
TailwindCSS
package showcase
import "github.com/axzilla/templui/components"
templ ButtonDefault() {
@components.Button() {
Button
}
}
package components
import (
"github.com/axzilla/templui/utils"
"strings"
)
type ButtonVariant string
type ButtonSize string
const (
ButtonVariantDefault ButtonVariant = "default"
ButtonVariantDestructive ButtonVariant = "destructive"
ButtonVariantOutline ButtonVariant = "outline"
ButtonVariantSecondary ButtonVariant = "secondary"
ButtonVariantGhost ButtonVariant = "ghost"
ButtonVariantLink ButtonVariant = "link"
)
const (
ButtonSizeIcon ButtonSize = "icon"
)
type ButtonProps struct {
ID string
Class string
Attributes templ.Attributes
Variant ButtonVariant
Size ButtonSize
FullWidth bool
Href string
Target string
Disabled bool
Type string
HxGet string
HxPost string
HxPut string
HxDelete string
HxTrigger string
HxTarget string
HxSwap string
HxReplaceUrl string
}
templ Button(props ...ButtonProps) {
{{ var p ButtonProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
if p.Href != "" && !p.Disabled {
<a
if p.ID != "" {
id={ p.ID }
}
href={ templ.SafeURL(p.Href) }
if p.Target != "" {
target={ p.Target }
}
class={
utils.TwMerge(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors",
"focus-visible:outline-hidden focus-visible:ring-2 focus:ring-ring focus-visible:ring-offset-2",
"cursor-pointer",
p.variantClasses(),
p.sizeClasses(),
p.modifierClasses(),
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</a>
} else {
<button
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors",
"focus-visible:outline-hidden focus-visible:ring-2 focus:ring-ring focus-visible:ring-offset-2",
"disabled:opacity-50 disabled:cursor-not-allowed",
"cursor-pointer",
p.variantClasses(),
p.sizeClasses(),
p.modifierClasses(),
p.Class,
),
}
if p.Type != "" {
type={ p.Type }
}
disabled?={ p.Disabled }
if p.HxGet != "" {
hx-get={ p.HxGet }
}
if p.HxPost != "" {
hx-post={ p.HxPost }
}
if p.HxPut != "" {
hx-put={ p.HxPut }
}
if p.HxDelete != "" {
hx-delete={ p.HxDelete }
}
if p.HxTrigger != "" {
hx-trigger={ p.HxTrigger }
}
if p.HxTarget != "" {
hx-target={ p.HxTarget }
}
if p.HxSwap != "" {
hx-swap={ p.HxSwap }
}
if p.HxReplaceUrl != "" {
hx-replace-url={ p.HxReplaceUrl }
}
{ p.Attributes... }
>
{ children... }
</button>
}
}
func (b ButtonProps) variantClasses() string {
switch b.Variant {
case ButtonVariantDestructive:
return "bg-destructive text-destructive-foreground hover:bg-destructive/90"
case ButtonVariantOutline:
return "border border-input bg-background hover:bg-accent hover:text-accent-foreground"
case ButtonVariantSecondary:
return "bg-secondary text-secondary-foreground hover:bg-secondary/80"
case ButtonVariantGhost:
return "hover:bg-accent hover:text-accent-foreground"
case ButtonVariantLink:
return "text-primary underline-offset-4 hover:underline"
default:
return "bg-primary text-primary-foreground hover:bg-primary/90"
}
}
func (b ButtonProps) sizeClasses() string {
switch b.Size {
case ButtonSizeIcon:
return "h-10 w-10"
default:
return "h-10 px-4 py-2 rounded-md"
}
}
func (b ButtonProps) modifierClasses() string {
classes := []string{}
if b.FullWidth {
classes = append(classes, "w-full")
}
return strings.Join(classes, " ")
}
Usage
@components.Button(components.ButtonProps{...})
Examples
Primary
package showcase
import "github.com/axzilla/templui/components"
templ ButtonPrimary() {
@components.Button() {
Primary
}
}
package components
import (
"github.com/axzilla/templui/utils"
"strings"
)
type ButtonVariant string
type ButtonSize string
const (
ButtonVariantDefault ButtonVariant = "default"
ButtonVariantDestructive ButtonVariant = "destructive"
ButtonVariantOutline ButtonVariant = "outline"
ButtonVariantSecondary ButtonVariant = "secondary"
ButtonVariantGhost ButtonVariant = "ghost"
ButtonVariantLink ButtonVariant = "link"
)
const (
ButtonSizeIcon ButtonSize = "icon"
)
type ButtonProps struct {
ID string
Class string
Attributes templ.Attributes
Variant ButtonVariant
Size ButtonSize
FullWidth bool
Href string
Target string
Disabled bool
Type string
HxGet string
HxPost string
HxPut string
HxDelete string
HxTrigger string
HxTarget string
HxSwap string
HxReplaceUrl string
}
templ Button(props ...ButtonProps) {
{{ var p ButtonProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
if p.Href != "" && !p.Disabled {
<a
if p.ID != "" {
id={ p.ID }
}
href={ templ.SafeURL(p.Href) }
if p.Target != "" {
target={ p.Target }
}
class={
utils.TwMerge(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors",
"focus-visible:outline-hidden focus-visible:ring-2 focus:ring-ring focus-visible:ring-offset-2",
"cursor-pointer",
p.variantClasses(),
p.sizeClasses(),
p.modifierClasses(),
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</a>
} else {
<button
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors",
"focus-visible:outline-hidden focus-visible:ring-2 focus:ring-ring focus-visible:ring-offset-2",
"disabled:opacity-50 disabled:cursor-not-allowed",
"cursor-pointer",
p.variantClasses(),
p.sizeClasses(),
p.modifierClasses(),
p.Class,
),
}
if p.Type != "" {
type={ p.Type }
}
disabled?={ p.Disabled }
if p.HxGet != "" {
hx-get={ p.HxGet }
}
if p.HxPost != "" {
hx-post={ p.HxPost }
}
if p.HxPut != "" {
hx-put={ p.HxPut }
}
if p.HxDelete != "" {
hx-delete={ p.HxDelete }
}
if p.HxTrigger != "" {
hx-trigger={ p.HxTrigger }
}
if p.HxTarget != "" {
hx-target={ p.HxTarget }
}
if p.HxSwap != "" {
hx-swap={ p.HxSwap }
}
if p.HxReplaceUrl != "" {
hx-replace-url={ p.HxReplaceUrl }
}
{ p.Attributes... }
>
{ children... }
</button>
}
}
func (b ButtonProps) variantClasses() string {
switch b.Variant {
case ButtonVariantDestructive:
return "bg-destructive text-destructive-foreground hover:bg-destructive/90"
case ButtonVariantOutline:
return "border border-input bg-background hover:bg-accent hover:text-accent-foreground"
case ButtonVariantSecondary:
return "bg-secondary text-secondary-foreground hover:bg-secondary/80"
case ButtonVariantGhost:
return "hover:bg-accent hover:text-accent-foreground"
case ButtonVariantLink:
return "text-primary underline-offset-4 hover:underline"
default:
return "bg-primary text-primary-foreground hover:bg-primary/90"
}
}
func (b ButtonProps) sizeClasses() string {
switch b.Size {
case ButtonSizeIcon:
return "h-10 w-10"
default:
return "h-10 px-4 py-2 rounded-md"
}
}
func (b ButtonProps) modifierClasses() string {
classes := []string{}
if b.FullWidth {
classes = append(classes, "w-full")
}
return strings.Join(classes, " ")
}
Secondary
package showcase
import "github.com/axzilla/templui/components"
templ ButtonSecondary() {
@components.Button(components.ButtonProps{
Variant: components.ButtonVariantSecondary,
}) {
Secondary
}
}
package components
import (
"github.com/axzilla/templui/utils"
"strings"
)
type ButtonVariant string
type ButtonSize string
const (
ButtonVariantDefault ButtonVariant = "default"
ButtonVariantDestructive ButtonVariant = "destructive"
ButtonVariantOutline ButtonVariant = "outline"
ButtonVariantSecondary ButtonVariant = "secondary"
ButtonVariantGhost ButtonVariant = "ghost"
ButtonVariantLink ButtonVariant = "link"
)
const (
ButtonSizeIcon ButtonSize = "icon"
)
type ButtonProps struct {
ID string
Class string
Attributes templ.Attributes
Variant ButtonVariant
Size ButtonSize
FullWidth bool
Href string
Target string
Disabled bool
Type string
HxGet string
HxPost string
HxPut string
HxDelete string
HxTrigger string
HxTarget string
HxSwap string
HxReplaceUrl string
}
templ Button(props ...ButtonProps) {
{{ var p ButtonProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
if p.Href != "" && !p.Disabled {
<a
if p.ID != "" {
id={ p.ID }
}
href={ templ.SafeURL(p.Href) }
if p.Target != "" {
target={ p.Target }
}
class={
utils.TwMerge(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors",
"focus-visible:outline-hidden focus-visible:ring-2 focus:ring-ring focus-visible:ring-offset-2",
"cursor-pointer",
p.variantClasses(),
p.sizeClasses(),
p.modifierClasses(),
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</a>
} else {
<button
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors",
"focus-visible:outline-hidden focus-visible:ring-2 focus:ring-ring focus-visible:ring-offset-2",
"disabled:opacity-50 disabled:cursor-not-allowed",
"cursor-pointer",
p.variantClasses(),
p.sizeClasses(),
p.modifierClasses(),
p.Class,
),
}
if p.Type != "" {
type={ p.Type }
}
disabled?={ p.Disabled }
if p.HxGet != "" {
hx-get={ p.HxGet }
}
if p.HxPost != "" {
hx-post={ p.HxPost }
}
if p.HxPut != "" {
hx-put={ p.HxPut }
}
if p.HxDelete != "" {
hx-delete={ p.HxDelete }
}
if p.HxTrigger != "" {
hx-trigger={ p.HxTrigger }
}
if p.HxTarget != "" {
hx-target={ p.HxTarget }
}
if p.HxSwap != "" {
hx-swap={ p.HxSwap }
}
if p.HxReplaceUrl != "" {
hx-replace-url={ p.HxReplaceUrl }
}
{ p.Attributes... }
>
{ children... }
</button>
}
}
func (b ButtonProps) variantClasses() string {
switch b.Variant {
case ButtonVariantDestructive:
return "bg-destructive text-destructive-foreground hover:bg-destructive/90"
case ButtonVariantOutline:
return "border border-input bg-background hover:bg-accent hover:text-accent-foreground"
case ButtonVariantSecondary:
return "bg-secondary text-secondary-foreground hover:bg-secondary/80"
case ButtonVariantGhost:
return "hover:bg-accent hover:text-accent-foreground"
case ButtonVariantLink:
return "text-primary underline-offset-4 hover:underline"
default:
return "bg-primary text-primary-foreground hover:bg-primary/90"
}
}
func (b ButtonProps) sizeClasses() string {
switch b.Size {
case ButtonSizeIcon:
return "h-10 w-10"
default:
return "h-10 px-4 py-2 rounded-md"
}
}
func (b ButtonProps) modifierClasses() string {
classes := []string{}
if b.FullWidth {
classes = append(classes, "w-full")
}
return strings.Join(classes, " ")
}
Destructive
package showcase
import "github.com/axzilla/templui/components"
templ ButtonDestructive() {
@components.Button(components.ButtonProps{
Variant: components.ButtonVariantDestructive,
}) {
Destructive
}
}
package components
import (
"github.com/axzilla/templui/utils"
"strings"
)
type ButtonVariant string
type ButtonSize string
const (
ButtonVariantDefault ButtonVariant = "default"
ButtonVariantDestructive ButtonVariant = "destructive"
ButtonVariantOutline ButtonVariant = "outline"
ButtonVariantSecondary ButtonVariant = "secondary"
ButtonVariantGhost ButtonVariant = "ghost"
ButtonVariantLink ButtonVariant = "link"
)
const (
ButtonSizeIcon ButtonSize = "icon"
)
type ButtonProps struct {
ID string
Class string
Attributes templ.Attributes
Variant ButtonVariant
Size ButtonSize
FullWidth bool
Href string
Target string
Disabled bool
Type string
HxGet string
HxPost string
HxPut string
HxDelete string
HxTrigger string
HxTarget string
HxSwap string
HxReplaceUrl string
}
templ Button(props ...ButtonProps) {
{{ var p ButtonProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
if p.Href != "" && !p.Disabled {
<a
if p.ID != "" {
id={ p.ID }
}
href={ templ.SafeURL(p.Href) }
if p.Target != "" {
target={ p.Target }
}
class={
utils.TwMerge(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors",
"focus-visible:outline-hidden focus-visible:ring-2 focus:ring-ring focus-visible:ring-offset-2",
"cursor-pointer",
p.variantClasses(),
p.sizeClasses(),
p.modifierClasses(),
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</a>
} else {
<button
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors",
"focus-visible:outline-hidden focus-visible:ring-2 focus:ring-ring focus-visible:ring-offset-2",
"disabled:opacity-50 disabled:cursor-not-allowed",
"cursor-pointer",
p.variantClasses(),
p.sizeClasses(),
p.modifierClasses(),
p.Class,
),
}
if p.Type != "" {
type={ p.Type }
}
disabled?={ p.Disabled }
if p.HxGet != "" {
hx-get={ p.HxGet }
}
if p.HxPost != "" {
hx-post={ p.HxPost }
}
if p.HxPut != "" {
hx-put={ p.HxPut }
}
if p.HxDelete != "" {
hx-delete={ p.HxDelete }
}
if p.HxTrigger != "" {
hx-trigger={ p.HxTrigger }
}
if p.HxTarget != "" {
hx-target={ p.HxTarget }
}
if p.HxSwap != "" {
hx-swap={ p.HxSwap }
}
if p.HxReplaceUrl != "" {
hx-replace-url={ p.HxReplaceUrl }
}
{ p.Attributes... }
>
{ children... }
</button>
}
}
func (b ButtonProps) variantClasses() string {
switch b.Variant {
case ButtonVariantDestructive:
return "bg-destructive text-destructive-foreground hover:bg-destructive/90"
case ButtonVariantOutline:
return "border border-input bg-background hover:bg-accent hover:text-accent-foreground"
case ButtonVariantSecondary:
return "bg-secondary text-secondary-foreground hover:bg-secondary/80"
case ButtonVariantGhost:
return "hover:bg-accent hover:text-accent-foreground"
case ButtonVariantLink:
return "text-primary underline-offset-4 hover:underline"
default:
return "bg-primary text-primary-foreground hover:bg-primary/90"
}
}
func (b ButtonProps) sizeClasses() string {
switch b.Size {
case ButtonSizeIcon:
return "h-10 w-10"
default:
return "h-10 px-4 py-2 rounded-md"
}
}
func (b ButtonProps) modifierClasses() string {
classes := []string{}
if b.FullWidth {
classes = append(classes, "w-full")
}
return strings.Join(classes, " ")
}
Outline
package showcase
import "github.com/axzilla/templui/components"
templ ButtonOutline() {
@components.Button(components.ButtonProps{
Variant: components.ButtonVariantOutline,
}) {
Outline
}
}
package components
import (
"github.com/axzilla/templui/utils"
"strings"
)
type ButtonVariant string
type ButtonSize string
const (
ButtonVariantDefault ButtonVariant = "default"
ButtonVariantDestructive ButtonVariant = "destructive"
ButtonVariantOutline ButtonVariant = "outline"
ButtonVariantSecondary ButtonVariant = "secondary"
ButtonVariantGhost ButtonVariant = "ghost"
ButtonVariantLink ButtonVariant = "link"
)
const (
ButtonSizeIcon ButtonSize = "icon"
)
type ButtonProps struct {
ID string
Class string
Attributes templ.Attributes
Variant ButtonVariant
Size ButtonSize
FullWidth bool
Href string
Target string
Disabled bool
Type string
HxGet string
HxPost string
HxPut string
HxDelete string
HxTrigger string
HxTarget string
HxSwap string
HxReplaceUrl string
}
templ Button(props ...ButtonProps) {
{{ var p ButtonProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
if p.Href != "" && !p.Disabled {
<a
if p.ID != "" {
id={ p.ID }
}
href={ templ.SafeURL(p.Href) }
if p.Target != "" {
target={ p.Target }
}
class={
utils.TwMerge(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors",
"focus-visible:outline-hidden focus-visible:ring-2 focus:ring-ring focus-visible:ring-offset-2",
"cursor-pointer",
p.variantClasses(),
p.sizeClasses(),
p.modifierClasses(),
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</a>
} else {
<button
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors",
"focus-visible:outline-hidden focus-visible:ring-2 focus:ring-ring focus-visible:ring-offset-2",
"disabled:opacity-50 disabled:cursor-not-allowed",
"cursor-pointer",
p.variantClasses(),
p.sizeClasses(),
p.modifierClasses(),
p.Class,
),
}
if p.Type != "" {
type={ p.Type }
}
disabled?={ p.Disabled }
if p.HxGet != "" {
hx-get={ p.HxGet }
}
if p.HxPost != "" {
hx-post={ p.HxPost }
}
if p.HxPut != "" {
hx-put={ p.HxPut }
}
if p.HxDelete != "" {
hx-delete={ p.HxDelete }
}
if p.HxTrigger != "" {
hx-trigger={ p.HxTrigger }
}
if p.HxTarget != "" {
hx-target={ p.HxTarget }
}
if p.HxSwap != "" {
hx-swap={ p.HxSwap }
}
if p.HxReplaceUrl != "" {
hx-replace-url={ p.HxReplaceUrl }
}
{ p.Attributes... }
>
{ children... }
</button>
}
}
func (b ButtonProps) variantClasses() string {
switch b.Variant {
case ButtonVariantDestructive:
return "bg-destructive text-destructive-foreground hover:bg-destructive/90"
case ButtonVariantOutline:
return "border border-input bg-background hover:bg-accent hover:text-accent-foreground"
case ButtonVariantSecondary:
return "bg-secondary text-secondary-foreground hover:bg-secondary/80"
case ButtonVariantGhost:
return "hover:bg-accent hover:text-accent-foreground"
case ButtonVariantLink:
return "text-primary underline-offset-4 hover:underline"
default:
return "bg-primary text-primary-foreground hover:bg-primary/90"
}
}
func (b ButtonProps) sizeClasses() string {
switch b.Size {
case ButtonSizeIcon:
return "h-10 w-10"
default:
return "h-10 px-4 py-2 rounded-md"
}
}
func (b ButtonProps) modifierClasses() string {
classes := []string{}
if b.FullWidth {
classes = append(classes, "w-full")
}
return strings.Join(classes, " ")
}
Ghost
package showcase
import "github.com/axzilla/templui/components"
templ ButtonGhost() {
@components.Button(components.ButtonProps{
Variant: components.ButtonVariantGhost,
}) {
Ghost
}
}
package components
import (
"github.com/axzilla/templui/utils"
"strings"
)
type ButtonVariant string
type ButtonSize string
const (
ButtonVariantDefault ButtonVariant = "default"
ButtonVariantDestructive ButtonVariant = "destructive"
ButtonVariantOutline ButtonVariant = "outline"
ButtonVariantSecondary ButtonVariant = "secondary"
ButtonVariantGhost ButtonVariant = "ghost"
ButtonVariantLink ButtonVariant = "link"
)
const (
ButtonSizeIcon ButtonSize = "icon"
)
type ButtonProps struct {
ID string
Class string
Attributes templ.Attributes
Variant ButtonVariant
Size ButtonSize
FullWidth bool
Href string
Target string
Disabled bool
Type string
HxGet string
HxPost string
HxPut string
HxDelete string
HxTrigger string
HxTarget string
HxSwap string
HxReplaceUrl string
}
templ Button(props ...ButtonProps) {
{{ var p ButtonProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
if p.Href != "" && !p.Disabled {
<a
if p.ID != "" {
id={ p.ID }
}
href={ templ.SafeURL(p.Href) }
if p.Target != "" {
target={ p.Target }
}
class={
utils.TwMerge(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors",
"focus-visible:outline-hidden focus-visible:ring-2 focus:ring-ring focus-visible:ring-offset-2",
"cursor-pointer",
p.variantClasses(),
p.sizeClasses(),
p.modifierClasses(),
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</a>
} else {
<button
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors",
"focus-visible:outline-hidden focus-visible:ring-2 focus:ring-ring focus-visible:ring-offset-2",
"disabled:opacity-50 disabled:cursor-not-allowed",
"cursor-pointer",
p.variantClasses(),
p.sizeClasses(),
p.modifierClasses(),
p.Class,
),
}
if p.Type != "" {
type={ p.Type }
}
disabled?={ p.Disabled }
if p.HxGet != "" {
hx-get={ p.HxGet }
}
if p.HxPost != "" {
hx-post={ p.HxPost }
}
if p.HxPut != "" {
hx-put={ p.HxPut }
}
if p.HxDelete != "" {
hx-delete={ p.HxDelete }
}
if p.HxTrigger != "" {
hx-trigger={ p.HxTrigger }
}
if p.HxTarget != "" {
hx-target={ p.HxTarget }
}
if p.HxSwap != "" {
hx-swap={ p.HxSwap }
}
if p.HxReplaceUrl != "" {
hx-replace-url={ p.HxReplaceUrl }
}
{ p.Attributes... }
>
{ children... }
</button>
}
}
func (b ButtonProps) variantClasses() string {
switch b.Variant {
case ButtonVariantDestructive:
return "bg-destructive text-destructive-foreground hover:bg-destructive/90"
case ButtonVariantOutline:
return "border border-input bg-background hover:bg-accent hover:text-accent-foreground"
case ButtonVariantSecondary:
return "bg-secondary text-secondary-foreground hover:bg-secondary/80"
case ButtonVariantGhost:
return "hover:bg-accent hover:text-accent-foreground"
case ButtonVariantLink:
return "text-primary underline-offset-4 hover:underline"
default:
return "bg-primary text-primary-foreground hover:bg-primary/90"
}
}
func (b ButtonProps) sizeClasses() string {
switch b.Size {
case ButtonSizeIcon:
return "h-10 w-10"
default:
return "h-10 px-4 py-2 rounded-md"
}
}
func (b ButtonProps) modifierClasses() string {
classes := []string{}
if b.FullWidth {
classes = append(classes, "w-full")
}
return strings.Join(classes, " ")
}
Link
package showcase
import "github.com/axzilla/templui/components"
templ ButtonLink() {
@components.Button(components.ButtonProps{
Variant: components.ButtonVariantLink,
}) {
Link
}
}
package components
import (
"github.com/axzilla/templui/utils"
"strings"
)
type ButtonVariant string
type ButtonSize string
const (
ButtonVariantDefault ButtonVariant = "default"
ButtonVariantDestructive ButtonVariant = "destructive"
ButtonVariantOutline ButtonVariant = "outline"
ButtonVariantSecondary ButtonVariant = "secondary"
ButtonVariantGhost ButtonVariant = "ghost"
ButtonVariantLink ButtonVariant = "link"
)
const (
ButtonSizeIcon ButtonSize = "icon"
)
type ButtonProps struct {
ID string
Class string
Attributes templ.Attributes
Variant ButtonVariant
Size ButtonSize
FullWidth bool
Href string
Target string
Disabled bool
Type string
HxGet string
HxPost string
HxPut string
HxDelete string
HxTrigger string
HxTarget string
HxSwap string
HxReplaceUrl string
}
templ Button(props ...ButtonProps) {
{{ var p ButtonProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
if p.Href != "" && !p.Disabled {
<a
if p.ID != "" {
id={ p.ID }
}
href={ templ.SafeURL(p.Href) }
if p.Target != "" {
target={ p.Target }
}
class={
utils.TwMerge(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors",
"focus-visible:outline-hidden focus-visible:ring-2 focus:ring-ring focus-visible:ring-offset-2",
"cursor-pointer",
p.variantClasses(),
p.sizeClasses(),
p.modifierClasses(),
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</a>
} else {
<button
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors",
"focus-visible:outline-hidden focus-visible:ring-2 focus:ring-ring focus-visible:ring-offset-2",
"disabled:opacity-50 disabled:cursor-not-allowed",
"cursor-pointer",
p.variantClasses(),
p.sizeClasses(),
p.modifierClasses(),
p.Class,
),
}
if p.Type != "" {
type={ p.Type }
}
disabled?={ p.Disabled }
if p.HxGet != "" {
hx-get={ p.HxGet }
}
if p.HxPost != "" {
hx-post={ p.HxPost }
}
if p.HxPut != "" {
hx-put={ p.HxPut }
}
if p.HxDelete != "" {
hx-delete={ p.HxDelete }
}
if p.HxTrigger != "" {
hx-trigger={ p.HxTrigger }
}
if p.HxTarget != "" {
hx-target={ p.HxTarget }
}
if p.HxSwap != "" {
hx-swap={ p.HxSwap }
}
if p.HxReplaceUrl != "" {
hx-replace-url={ p.HxReplaceUrl }
}
{ p.Attributes... }
>
{ children... }
</button>
}
}
func (b ButtonProps) variantClasses() string {
switch b.Variant {
case ButtonVariantDestructive:
return "bg-destructive text-destructive-foreground hover:bg-destructive/90"
case ButtonVariantOutline:
return "border border-input bg-background hover:bg-accent hover:text-accent-foreground"
case ButtonVariantSecondary:
return "bg-secondary text-secondary-foreground hover:bg-secondary/80"
case ButtonVariantGhost:
return "hover:bg-accent hover:text-accent-foreground"
case ButtonVariantLink:
return "text-primary underline-offset-4 hover:underline"
default:
return "bg-primary text-primary-foreground hover:bg-primary/90"
}
}
func (b ButtonProps) sizeClasses() string {
switch b.Size {
case ButtonSizeIcon:
return "h-10 w-10"
default:
return "h-10 px-4 py-2 rounded-md"
}
}
func (b ButtonProps) modifierClasses() string {
classes := []string{}
if b.FullWidth {
classes = append(classes, "w-full")
}
return strings.Join(classes, " ")
}
Icon
package showcase
import (
"github.com/axzilla/templui/components"
"github.com/axzilla/templui/icons"
)
templ ButtonIcon() {
@components.Button(components.ButtonProps{
Size: components.ButtonSizeIcon,
Variant: components.ButtonVariantOutline,
}) {
@icons.ChevronRight(icons.IconProps{Size: 16})
}
}
package components
import (
"github.com/axzilla/templui/utils"
"strings"
)
type ButtonVariant string
type ButtonSize string
const (
ButtonVariantDefault ButtonVariant = "default"
ButtonVariantDestructive ButtonVariant = "destructive"
ButtonVariantOutline ButtonVariant = "outline"
ButtonVariantSecondary ButtonVariant = "secondary"
ButtonVariantGhost ButtonVariant = "ghost"
ButtonVariantLink ButtonVariant = "link"
)
const (
ButtonSizeIcon ButtonSize = "icon"
)
type ButtonProps struct {
ID string
Class string
Attributes templ.Attributes
Variant ButtonVariant
Size ButtonSize
FullWidth bool
Href string
Target string
Disabled bool
Type string
HxGet string
HxPost string
HxPut string
HxDelete string
HxTrigger string
HxTarget string
HxSwap string
HxReplaceUrl string
}
templ Button(props ...ButtonProps) {
{{ var p ButtonProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
if p.Href != "" && !p.Disabled {
<a
if p.ID != "" {
id={ p.ID }
}
href={ templ.SafeURL(p.Href) }
if p.Target != "" {
target={ p.Target }
}
class={
utils.TwMerge(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors",
"focus-visible:outline-hidden focus-visible:ring-2 focus:ring-ring focus-visible:ring-offset-2",
"cursor-pointer",
p.variantClasses(),
p.sizeClasses(),
p.modifierClasses(),
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</a>
} else {
<button
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors",
"focus-visible:outline-hidden focus-visible:ring-2 focus:ring-ring focus-visible:ring-offset-2",
"disabled:opacity-50 disabled:cursor-not-allowed",
"cursor-pointer",
p.variantClasses(),
p.sizeClasses(),
p.modifierClasses(),
p.Class,
),
}
if p.Type != "" {
type={ p.Type }
}
disabled?={ p.Disabled }
if p.HxGet != "" {
hx-get={ p.HxGet }
}
if p.HxPost != "" {
hx-post={ p.HxPost }
}
if p.HxPut != "" {
hx-put={ p.HxPut }
}
if p.HxDelete != "" {
hx-delete={ p.HxDelete }
}
if p.HxTrigger != "" {
hx-trigger={ p.HxTrigger }
}
if p.HxTarget != "" {
hx-target={ p.HxTarget }
}
if p.HxSwap != "" {
hx-swap={ p.HxSwap }
}
if p.HxReplaceUrl != "" {
hx-replace-url={ p.HxReplaceUrl }
}
{ p.Attributes... }
>
{ children... }
</button>
}
}
func (b ButtonProps) variantClasses() string {
switch b.Variant {
case ButtonVariantDestructive:
return "bg-destructive text-destructive-foreground hover:bg-destructive/90"
case ButtonVariantOutline:
return "border border-input bg-background hover:bg-accent hover:text-accent-foreground"
case ButtonVariantSecondary:
return "bg-secondary text-secondary-foreground hover:bg-secondary/80"
case ButtonVariantGhost:
return "hover:bg-accent hover:text-accent-foreground"
case ButtonVariantLink:
return "text-primary underline-offset-4 hover:underline"
default:
return "bg-primary text-primary-foreground hover:bg-primary/90"
}
}
func (b ButtonProps) sizeClasses() string {
switch b.Size {
case ButtonSizeIcon:
return "h-10 w-10"
default:
return "h-10 px-4 py-2 rounded-md"
}
}
func (b ButtonProps) modifierClasses() string {
classes := []string{}
if b.FullWidth {
classes = append(classes, "w-full")
}
return strings.Join(classes, " ")
}
With Icon
package showcase
import (
"github.com/axzilla/templui/components"
"github.com/axzilla/templui/icons"
)
templ ButtonIcon() {
@components.Button(components.ButtonProps{
Size: components.ButtonSizeIcon,
Variant: components.ButtonVariantOutline,
}) {
@icons.ChevronRight(icons.IconProps{Size: 16})
}
}
package components
import (
"github.com/axzilla/templui/utils"
"strings"
)
type ButtonVariant string
type ButtonSize string
const (
ButtonVariantDefault ButtonVariant = "default"
ButtonVariantDestructive ButtonVariant = "destructive"
ButtonVariantOutline ButtonVariant = "outline"
ButtonVariantSecondary ButtonVariant = "secondary"
ButtonVariantGhost ButtonVariant = "ghost"
ButtonVariantLink ButtonVariant = "link"
)
const (
ButtonSizeIcon ButtonSize = "icon"
)
type ButtonProps struct {
ID string
Class string
Attributes templ.Attributes
Variant ButtonVariant
Size ButtonSize
FullWidth bool
Href string
Target string
Disabled bool
Type string
HxGet string
HxPost string
HxPut string
HxDelete string
HxTrigger string
HxTarget string
HxSwap string
HxReplaceUrl string
}
templ Button(props ...ButtonProps) {
{{ var p ButtonProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
if p.Href != "" && !p.Disabled {
<a
if p.ID != "" {
id={ p.ID }
}
href={ templ.SafeURL(p.Href) }
if p.Target != "" {
target={ p.Target }
}
class={
utils.TwMerge(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors",
"focus-visible:outline-hidden focus-visible:ring-2 focus:ring-ring focus-visible:ring-offset-2",
"cursor-pointer",
p.variantClasses(),
p.sizeClasses(),
p.modifierClasses(),
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</a>
} else {
<button
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors",
"focus-visible:outline-hidden focus-visible:ring-2 focus:ring-ring focus-visible:ring-offset-2",
"disabled:opacity-50 disabled:cursor-not-allowed",
"cursor-pointer",
p.variantClasses(),
p.sizeClasses(),
p.modifierClasses(),
p.Class,
),
}
if p.Type != "" {
type={ p.Type }
}
disabled?={ p.Disabled }
if p.HxGet != "" {
hx-get={ p.HxGet }
}
if p.HxPost != "" {
hx-post={ p.HxPost }
}
if p.HxPut != "" {
hx-put={ p.HxPut }
}
if p.HxDelete != "" {
hx-delete={ p.HxDelete }
}
if p.HxTrigger != "" {
hx-trigger={ p.HxTrigger }
}
if p.HxTarget != "" {
hx-target={ p.HxTarget }
}
if p.HxSwap != "" {
hx-swap={ p.HxSwap }
}
if p.HxReplaceUrl != "" {
hx-replace-url={ p.HxReplaceUrl }
}
{ p.Attributes... }
>
{ children... }
</button>
}
}
func (b ButtonProps) variantClasses() string {
switch b.Variant {
case ButtonVariantDestructive:
return "bg-destructive text-destructive-foreground hover:bg-destructive/90"
case ButtonVariantOutline:
return "border border-input bg-background hover:bg-accent hover:text-accent-foreground"
case ButtonVariantSecondary:
return "bg-secondary text-secondary-foreground hover:bg-secondary/80"
case ButtonVariantGhost:
return "hover:bg-accent hover:text-accent-foreground"
case ButtonVariantLink:
return "text-primary underline-offset-4 hover:underline"
default:
return "bg-primary text-primary-foreground hover:bg-primary/90"
}
}
func (b ButtonProps) sizeClasses() string {
switch b.Size {
case ButtonSizeIcon:
return "h-10 w-10"
default:
return "h-10 px-4 py-2 rounded-md"
}
}
func (b ButtonProps) modifierClasses() string {
classes := []string{}
if b.FullWidth {
classes = append(classes, "w-full")
}
return strings.Join(classes, " ")
}
Loading
package showcase
import "github.com/axzilla/templui/components"
templ ButtonLoading() {
@components.Button(components.ButtonProps{
Disabled: true,
Class: "flex items-center gap-2",
}) {
@components.Spinner(components.SpinnerProps{
Size: components.SpinnerSizeSm,
Color: "text-primary-foreground",
})
Pleae wait
}
}
package components
import (
"github.com/axzilla/templui/utils"
"strings"
)
type ButtonVariant string
type ButtonSize string
const (
ButtonVariantDefault ButtonVariant = "default"
ButtonVariantDestructive ButtonVariant = "destructive"
ButtonVariantOutline ButtonVariant = "outline"
ButtonVariantSecondary ButtonVariant = "secondary"
ButtonVariantGhost ButtonVariant = "ghost"
ButtonVariantLink ButtonVariant = "link"
)
const (
ButtonSizeIcon ButtonSize = "icon"
)
type ButtonProps struct {
ID string
Class string
Attributes templ.Attributes
Variant ButtonVariant
Size ButtonSize
FullWidth bool
Href string
Target string
Disabled bool
Type string
HxGet string
HxPost string
HxPut string
HxDelete string
HxTrigger string
HxTarget string
HxSwap string
HxReplaceUrl string
}
templ Button(props ...ButtonProps) {
{{ var p ButtonProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
if p.Href != "" && !p.Disabled {
<a
if p.ID != "" {
id={ p.ID }
}
href={ templ.SafeURL(p.Href) }
if p.Target != "" {
target={ p.Target }
}
class={
utils.TwMerge(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors",
"focus-visible:outline-hidden focus-visible:ring-2 focus:ring-ring focus-visible:ring-offset-2",
"cursor-pointer",
p.variantClasses(),
p.sizeClasses(),
p.modifierClasses(),
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</a>
} else {
<button
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors",
"focus-visible:outline-hidden focus-visible:ring-2 focus:ring-ring focus-visible:ring-offset-2",
"disabled:opacity-50 disabled:cursor-not-allowed",
"cursor-pointer",
p.variantClasses(),
p.sizeClasses(),
p.modifierClasses(),
p.Class,
),
}
if p.Type != "" {
type={ p.Type }
}
disabled?={ p.Disabled }
if p.HxGet != "" {
hx-get={ p.HxGet }
}
if p.HxPost != "" {
hx-post={ p.HxPost }
}
if p.HxPut != "" {
hx-put={ p.HxPut }
}
if p.HxDelete != "" {
hx-delete={ p.HxDelete }
}
if p.HxTrigger != "" {
hx-trigger={ p.HxTrigger }
}
if p.HxTarget != "" {
hx-target={ p.HxTarget }
}
if p.HxSwap != "" {
hx-swap={ p.HxSwap }
}
if p.HxReplaceUrl != "" {
hx-replace-url={ p.HxReplaceUrl }
}
{ p.Attributes... }
>
{ children... }
</button>
}
}
func (b ButtonProps) variantClasses() string {
switch b.Variant {
case ButtonVariantDestructive:
return "bg-destructive text-destructive-foreground hover:bg-destructive/90"
case ButtonVariantOutline:
return "border border-input bg-background hover:bg-accent hover:text-accent-foreground"
case ButtonVariantSecondary:
return "bg-secondary text-secondary-foreground hover:bg-secondary/80"
case ButtonVariantGhost:
return "hover:bg-accent hover:text-accent-foreground"
case ButtonVariantLink:
return "text-primary underline-offset-4 hover:underline"
default:
return "bg-primary text-primary-foreground hover:bg-primary/90"
}
}
func (b ButtonProps) sizeClasses() string {
switch b.Size {
case ButtonSizeIcon:
return "h-10 w-10"
default:
return "h-10 px-4 py-2 rounded-md"
}
}
func (b ButtonProps) modifierClasses() string {
classes := []string{}
if b.FullWidth {
classes = append(classes, "w-full")
}
return strings.Join(classes, " ")
}
HTMX Loading (5s)
package showcase
import "github.com/axzilla/templui/components"
templ ButtonHtmxLoading() {
<div class="flex flex-wrap items-center gap-2">
<form
class="flex flex-col gap-2"
hx-post="/docs/button/htmx-loading"
hx-trigger="submit"
hx-indicator="#spinner"
hx-disabled-elt="find button"
>
@components.Button(components.ButtonProps{
Type: "submit",
Class: "flex items-center gap-2",
}) {
<span id="spinner" class="htmx-indicator hidden [&.htmx-request]:inline-flex">
@components.Spinner(components.SpinnerProps{
Size: components.SpinnerSizeSm,
Color: "text-primary-foreground",
})
</span>
Submit
}
</form>
<div id="toast-container"></div>
</div>
}
package components
import (
"github.com/axzilla/templui/utils"
"strings"
)
type ButtonVariant string
type ButtonSize string
const (
ButtonVariantDefault ButtonVariant = "default"
ButtonVariantDestructive ButtonVariant = "destructive"
ButtonVariantOutline ButtonVariant = "outline"
ButtonVariantSecondary ButtonVariant = "secondary"
ButtonVariantGhost ButtonVariant = "ghost"
ButtonVariantLink ButtonVariant = "link"
)
const (
ButtonSizeIcon ButtonSize = "icon"
)
type ButtonProps struct {
ID string
Class string
Attributes templ.Attributes
Variant ButtonVariant
Size ButtonSize
FullWidth bool
Href string
Target string
Disabled bool
Type string
HxGet string
HxPost string
HxPut string
HxDelete string
HxTrigger string
HxTarget string
HxSwap string
HxReplaceUrl string
}
templ Button(props ...ButtonProps) {
{{ var p ButtonProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
if p.Href != "" && !p.Disabled {
<a
if p.ID != "" {
id={ p.ID }
}
href={ templ.SafeURL(p.Href) }
if p.Target != "" {
target={ p.Target }
}
class={
utils.TwMerge(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors",
"focus-visible:outline-hidden focus-visible:ring-2 focus:ring-ring focus-visible:ring-offset-2",
"cursor-pointer",
p.variantClasses(),
p.sizeClasses(),
p.modifierClasses(),
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</a>
} else {
<button
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors",
"focus-visible:outline-hidden focus-visible:ring-2 focus:ring-ring focus-visible:ring-offset-2",
"disabled:opacity-50 disabled:cursor-not-allowed",
"cursor-pointer",
p.variantClasses(),
p.sizeClasses(),
p.modifierClasses(),
p.Class,
),
}
if p.Type != "" {
type={ p.Type }
}
disabled?={ p.Disabled }
if p.HxGet != "" {
hx-get={ p.HxGet }
}
if p.HxPost != "" {
hx-post={ p.HxPost }
}
if p.HxPut != "" {
hx-put={ p.HxPut }
}
if p.HxDelete != "" {
hx-delete={ p.HxDelete }
}
if p.HxTrigger != "" {
hx-trigger={ p.HxTrigger }
}
if p.HxTarget != "" {
hx-target={ p.HxTarget }
}
if p.HxSwap != "" {
hx-swap={ p.HxSwap }
}
if p.HxReplaceUrl != "" {
hx-replace-url={ p.HxReplaceUrl }
}
{ p.Attributes... }
>
{ children... }
</button>
}
}
func (b ButtonProps) variantClasses() string {
switch b.Variant {
case ButtonVariantDestructive:
return "bg-destructive text-destructive-foreground hover:bg-destructive/90"
case ButtonVariantOutline:
return "border border-input bg-background hover:bg-accent hover:text-accent-foreground"
case ButtonVariantSecondary:
return "bg-secondary text-secondary-foreground hover:bg-secondary/80"
case ButtonVariantGhost:
return "hover:bg-accent hover:text-accent-foreground"
case ButtonVariantLink:
return "text-primary underline-offset-4 hover:underline"
default:
return "bg-primary text-primary-foreground hover:bg-primary/90"
}
}
func (b ButtonProps) sizeClasses() string {
switch b.Size {
case ButtonSizeIcon:
return "h-10 w-10"
default:
return "h-10 px-4 py-2 rounded-md"
}
}
func (b ButtonProps) modifierClasses() string {
classes := []string{}
if b.FullWidth {
classes = append(classes, "w-full")
}
return strings.Join(classes, " ")
}