Button
Displays a button or a component that looks like a button.
Variants
Sizes
States
With Icon
package showcase
import "github.com/axzilla/goilerplate/internals/ui/components"
templ ButtonShowcase() {
<div class="space-y-8 border rounded-md p-4">
<h2 class="font-semibold mb-4">Variants</h2>
<div class="flex flex-wrap gap-2">
@components.Button(components.ButtonProps{Text: "Default"}, nil)
@components.Button(components.ButtonProps{Text: "Secondary", Variant: components.Secondary}, nil)
@components.Button(components.ButtonProps{Text: "Destructive", Variant: components.Destructive}, nil)
@components.Button(components.ButtonProps{Text: "Outline", Variant: components.Outline}, nil)
@components.Button(components.ButtonProps{Text: "Ghost", Variant: components.Ghost}, nil)
@components.Button(components.ButtonProps{Text: "Link", Variant: components.Link}, nil)
</div>
<h2 class="font-semibold mb-4">Sizes</h2>
<div class="flex flex-wrap items-center gap-2">
@components.Button(components.ButtonProps{Text: "Default"}, nil)
@components.Button(components.ButtonProps{Text: "Small", Size: components.Sm}, nil)
@components.Button(components.ButtonProps{Text: "Large", Size: components.Lg}, nil)
@components.Button(components.ButtonProps{Size: components.Icon}, nil) {
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="h-4 w-4"
>
<path d="M5 12h14"></path><path d="m12 5 7 7-7 7"></path>
</svg>
}
</div>
<h2 class="font-semibold mb-4">States</h2>
<div class="flex flex-wrap gap-2">
@components.Button(components.ButtonProps{Text: "Default"}, nil)
// Alpine.js example
@components.Button(components.ButtonProps{Text: "With Click"}, templ.Attributes{"@click": "alert('Hey Dude!')"})
// Vanilla JS example
// @components.Button(components.ButtonProps{Text: "With Click"}, templ.Attributes{"onclick": "alert('Hey Dude!')"})
@components.Button(components.ButtonProps{Text: "Disabled"}, templ.Attributes{"disabled": "true"})
@components.Button(components.ButtonProps{Text: "Full Width", Class: "w-full"}, nil)
</div>
<h2 class="font-semibold mb-4">With Icon</h2>
<div class="flex flex-wrap gap-2">
@components.Button(components.ButtonProps{}, nil) {
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="mr-2 h-4 w-4"
>
<path d="M15 6v12a3 3 0 1 0 3-3H6a3 3 0 1 0 3 3V6a3 3 0 1 0-3 3h12a3 3 0 1 0-3-3"></path>
</svg>
Icon Left
}
@components.Button(components.ButtonProps{}, nil) {
Icon Right
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="ml-2 h-4 w-4"
>
<path d="M15 6v12a3 3 0 1 0 3-3H6a3 3 0 1 0 3 3V6a3 3 0 1 0-3 3h12a3 3 0 1 0-3-3"></path>
</svg>
}
</div>
</div>
}
package components
type ButtonVariant string
type ButtonSize string
const (
Destructive ButtonVariant = "destructive"
Outline ButtonVariant = "outline"
Secondary ButtonVariant = "secondary"
Ghost ButtonVariant = "ghost"
Link ButtonVariant = "link"
Sm ButtonSize = "sm"
Lg ButtonSize = "lg"
Icon ButtonSize = "icon"
)
type ButtonProps struct {
Class string
Text string
Variant ButtonVariant
Size ButtonSize
FullWidth bool
Href string
Target string
}
func getVariantClasses(variant ButtonVariant) string {
switch variant {
case Destructive:
return "bg-destructive text-destructive-foreground hover:bg-destructive/90"
case Outline:
return "border border-input bg-background hover:bg-accent hover:text-accent-foreground"
case Secondary:
return "bg-secondary text-secondary-foreground hover:bg-secondary/80"
case Ghost:
return "hover:bg-accent hover:text-accent-foreground"
case Link:
return "text-primary underline-offset-4 hover:underline"
default:
return "bg-primary text-primary-foreground hover:bg-primary/90"
}
}
func getSizeClasses(size ButtonSize) string {
switch size {
case Sm:
return "h-9 px-3 rounded-md"
case Lg:
return "h-11 px-8 rounded-md"
case Icon:
return "h-10 w-10"
default:
return "h-10 px-4 py-2 rounded-md"
}
}
templ Button(props ButtonProps, attrs map[string]any) {
if props.Href != "" {
<a
{ attrs... }
href={ templ.SafeURL(props.Href) }
target={ props.Target }
class={
"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",
getVariantClasses(props.Variant),
getSizeClasses(props.Size),
templ.KV("w-full", props.FullWidth),
props.Class,
}
>
{ props.Text }
{ children... }
</a>
} else {
<button
{ attrs... }
class={
"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",
"disabled:pointer-events-none disabled:opacity-50",
getVariantClasses(props.Variant),
getSizeClasses(props.Size),
templ.KV("w-full", props.FullWidth),
props.Class,
}
>
{ props.Text }
{ children... }
</button>
}
}