Button
Interactive element that triggers actions when clicked.
TailwindCSS
package showcase
import "github.com/axzilla/templui/pkg/components"
templ ButtonVariants() {
<div class="flex flex-wrap gap-2">
@components.Button(components.ButtonProps{Text: "Default"})
@components.Button(components.ButtonProps{Text: "Secondary", Variant: components.ButtonVariantSecondary})
@components.Button(components.ButtonProps{Text: "Destructive", Variant: components.ButtonVariantDestructive})
@components.Button(components.ButtonProps{Text: "Outline", Variant: components.ButtonVariantOutline})
@components.Button(components.ButtonProps{Text: "Ghost", Variant: components.ButtonVariantGhost})
@components.Button(components.ButtonProps{Text: "Link", Variant: components.ButtonVariantLink})
</div>
}
package components
import (
"github.com/axzilla/templui/pkg/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"
ButtonSizeMd ButtonSize = "md"
ButtonSizeSm ButtonSize = "sm"
ButtonSizeLg ButtonSize = "lg"
ButtonSizeIcon ButtonSize = "icon"
)
type ButtonProps struct {
Class string // Additional CSS classes
Text string // Button label text
Variant ButtonVariant // Visual style (default, destructive, outline, secondary, ghost, link)
Size ButtonSize // Button dimensions (md, sm, lg, icon)
FullWidth bool // Expand to fill container
Href string // Optional URL for link buttons
Target string // Link target attribute (default: _self)
Disabled bool // Interactivity state
Type string // Button type attribute
IconLeft templ.Component // Icon component before text
IconRight templ.Component // Icon component after text
Attributes templ.Attributes // Additional HTML attributes
}
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 ButtonSizeSm:
return "h-9 px-3 rounded-md"
case ButtonSizeLg:
return "h-11 px-8 rounded-md"
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, " ")
}
// Interactive element that triggers actions when clicked.
templ Button(props ButtonProps) {
if props.Href != "" {
<a
href={ templ.SafeURL(props.Href) }
target={ props.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-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
props.variantClasses(),
props.sizeClasses(),
props.modifierClasses(),
props.Class,
),
}
if props.Disabled == true {
disabled
}
{ props.Attributes... }
>
{ children... }
@renderButtonContent(props)
</a>
} else {
<button
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-none focus-visible:ring-2 focus-ring-ring focus-visible:ring-offset-2",
"disabled:pointer-events-none disabled:opacity-50",
props.variantClasses(),
props.sizeClasses(),
props.modifierClasses(),
props.Class,
),
}
if props.Type != "" {
type={ props.Type }
}
disabled?={ props.Disabled }
{ props.Attributes... }
>
{ children... }
@renderButtonContent(props)
</button>
}
}
templ renderButtonContent(props ButtonProps) {
<span class="flex gap-2 items-center">
if props.IconLeft != nil {
@props.IconLeft
}
{ props.Text }
if props.IconRight != nil {
@props.IconRight
}
</span>
}
Usage
@components.Button(components.ButtonProps{...})
Examples
Sizes
package showcase
import (
"github.com/axzilla/templui/pkg/components"
"github.com/axzilla/templui/pkg/icons"
)
templ ButtonSizes() {
<div class="flex flex-wrap items-center gap-2">
@components.Button(components.ButtonProps{Text: "Small", Size: components.ButtonSizeSm})
@components.Button(components.ButtonProps{Text: "Default"})
@components.Button(components.ButtonProps{Text: "Large", Size: components.ButtonSizeLg})
@components.Button(components.ButtonProps{Size: components.ButtonSizeIcon, IconLeft: icons.Rocket(icons.IconProps{Size: "16"})})
</div>
}
package components
import (
"github.com/axzilla/templui/pkg/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"
ButtonSizeMd ButtonSize = "md"
ButtonSizeSm ButtonSize = "sm"
ButtonSizeLg ButtonSize = "lg"
ButtonSizeIcon ButtonSize = "icon"
)
type ButtonProps struct {
Class string // Additional CSS classes
Text string // Button label text
Variant ButtonVariant // Visual style (default, destructive, outline, secondary, ghost, link)
Size ButtonSize // Button dimensions (md, sm, lg, icon)
FullWidth bool // Expand to fill container
Href string // Optional URL for link buttons
Target string // Link target attribute (default: _self)
Disabled bool // Interactivity state
Type string // Button type attribute
IconLeft templ.Component // Icon component before text
IconRight templ.Component // Icon component after text
Attributes templ.Attributes // Additional HTML attributes
}
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 ButtonSizeSm:
return "h-9 px-3 rounded-md"
case ButtonSizeLg:
return "h-11 px-8 rounded-md"
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, " ")
}
// Interactive element that triggers actions when clicked.
templ Button(props ButtonProps) {
if props.Href != "" {
<a
href={ templ.SafeURL(props.Href) }
target={ props.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-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
props.variantClasses(),
props.sizeClasses(),
props.modifierClasses(),
props.Class,
),
}
if props.Disabled == true {
disabled
}
{ props.Attributes... }
>
{ children... }
@renderButtonContent(props)
</a>
} else {
<button
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-none focus-visible:ring-2 focus-ring-ring focus-visible:ring-offset-2",
"disabled:pointer-events-none disabled:opacity-50",
props.variantClasses(),
props.sizeClasses(),
props.modifierClasses(),
props.Class,
),
}
if props.Type != "" {
type={ props.Type }
}
disabled?={ props.Disabled }
{ props.Attributes... }
>
{ children... }
@renderButtonContent(props)
</button>
}
}
templ renderButtonContent(props ButtonProps) {
<span class="flex gap-2 items-center">
if props.IconLeft != nil {
@props.IconLeft
}
{ props.Text }
if props.IconRight != nil {
@props.IconRight
}
</span>
}
Disabled
package showcase
import "github.com/axzilla/templui/pkg/components"
templ ButtonDisabled() {
<div class="flex flex-wrap gap-2">
@components.Button(components.ButtonProps{Text: "Disabled", Disabled: true})
</div>
}
package components
import (
"github.com/axzilla/templui/pkg/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"
ButtonSizeMd ButtonSize = "md"
ButtonSizeSm ButtonSize = "sm"
ButtonSizeLg ButtonSize = "lg"
ButtonSizeIcon ButtonSize = "icon"
)
type ButtonProps struct {
Class string // Additional CSS classes
Text string // Button label text
Variant ButtonVariant // Visual style (default, destructive, outline, secondary, ghost, link)
Size ButtonSize // Button dimensions (md, sm, lg, icon)
FullWidth bool // Expand to fill container
Href string // Optional URL for link buttons
Target string // Link target attribute (default: _self)
Disabled bool // Interactivity state
Type string // Button type attribute
IconLeft templ.Component // Icon component before text
IconRight templ.Component // Icon component after text
Attributes templ.Attributes // Additional HTML attributes
}
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 ButtonSizeSm:
return "h-9 px-3 rounded-md"
case ButtonSizeLg:
return "h-11 px-8 rounded-md"
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, " ")
}
// Interactive element that triggers actions when clicked.
templ Button(props ButtonProps) {
if props.Href != "" {
<a
href={ templ.SafeURL(props.Href) }
target={ props.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-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
props.variantClasses(),
props.sizeClasses(),
props.modifierClasses(),
props.Class,
),
}
if props.Disabled == true {
disabled
}
{ props.Attributes... }
>
{ children... }
@renderButtonContent(props)
</a>
} else {
<button
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-none focus-visible:ring-2 focus-ring-ring focus-visible:ring-offset-2",
"disabled:pointer-events-none disabled:opacity-50",
props.variantClasses(),
props.sizeClasses(),
props.modifierClasses(),
props.Class,
),
}
if props.Type != "" {
type={ props.Type }
}
disabled?={ props.Disabled }
{ props.Attributes... }
>
{ children... }
@renderButtonContent(props)
</button>
}
}
templ renderButtonContent(props ButtonProps) {
<span class="flex gap-2 items-center">
if props.IconLeft != nil {
@props.IconLeft
}
{ props.Text }
if props.IconRight != nil {
@props.IconRight
}
</span>
}
Icons
package showcase
import (
"github.com/axzilla/templui/pkg/components"
"github.com/axzilla/templui/pkg/icons"
)
templ ButtonIcons() {
<div class="flex flex-wrap gap-2">
@components.Button(components.ButtonProps{
Text: "Icon Left",
IconLeft: icons.Rocket(icons.IconProps{Size: "16"}),
})
@components.Button(components.ButtonProps{
Text: "Icon Right",
IconRight: icons.Rocket(icons.IconProps{Size: "16"}),
})
</div>
}
package components
import (
"github.com/axzilla/templui/pkg/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"
ButtonSizeMd ButtonSize = "md"
ButtonSizeSm ButtonSize = "sm"
ButtonSizeLg ButtonSize = "lg"
ButtonSizeIcon ButtonSize = "icon"
)
type ButtonProps struct {
Class string // Additional CSS classes
Text string // Button label text
Variant ButtonVariant // Visual style (default, destructive, outline, secondary, ghost, link)
Size ButtonSize // Button dimensions (md, sm, lg, icon)
FullWidth bool // Expand to fill container
Href string // Optional URL for link buttons
Target string // Link target attribute (default: _self)
Disabled bool // Interactivity state
Type string // Button type attribute
IconLeft templ.Component // Icon component before text
IconRight templ.Component // Icon component after text
Attributes templ.Attributes // Additional HTML attributes
}
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 ButtonSizeSm:
return "h-9 px-3 rounded-md"
case ButtonSizeLg:
return "h-11 px-8 rounded-md"
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, " ")
}
// Interactive element that triggers actions when clicked.
templ Button(props ButtonProps) {
if props.Href != "" {
<a
href={ templ.SafeURL(props.Href) }
target={ props.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-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
props.variantClasses(),
props.sizeClasses(),
props.modifierClasses(),
props.Class,
),
}
if props.Disabled == true {
disabled
}
{ props.Attributes... }
>
{ children... }
@renderButtonContent(props)
</a>
} else {
<button
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-none focus-visible:ring-2 focus-ring-ring focus-visible:ring-offset-2",
"disabled:pointer-events-none disabled:opacity-50",
props.variantClasses(),
props.sizeClasses(),
props.modifierClasses(),
props.Class,
),
}
if props.Type != "" {
type={ props.Type }
}
disabled?={ props.Disabled }
{ props.Attributes... }
>
{ children... }
@renderButtonContent(props)
</button>
}
}
templ renderButtonContent(props ButtonProps) {
<span class="flex gap-2 items-center">
if props.IconLeft != nil {
@props.IconLeft
}
{ props.Text }
if props.IconRight != nil {
@props.IconRight
}
</span>
}