Primary
package showcase
import "github.com/axzilla/templui/internal/components/button"
templ ButtonPrimary() {
@button.Button() {
Primary
}
}
Interactive element that triggers actions when clicked.
package showcase
import "github.com/axzilla/templui/internal/components/button"
templ ButtonDefault() {
@button.Button() {
Button
}
}
templui add button
Copy and paste the following code into your project:
package button
import (
"github.com/axzilla/templui/internal/utils"
"strings"
)
type Variant string
type Size string
type Type string
const (
VariantDefault Variant = "default"
VariantDestructive Variant = "destructive"
VariantOutline Variant = "outline"
VariantSecondary Variant = "secondary"
VariantGhost Variant = "ghost"
VariantLink Variant = "link"
)
const (
TypeButton Type = "button"
TypeReset Type = "reset"
TypeSubmit Type = "submit"
)
const (
SizeIcon Size = "icon"
)
type Props struct {
ID string
Class string
Attributes templ.Attributes
Variant Variant
Size Size
FullWidth bool
Href string
Target string
Disabled bool
Type Type
HxGet string
HxPost string
HxPut string
HxDelete string
HxTrigger string
HxTarget string
HxSwap string
HxReplaceUrl string
}
templ Button(props ...Props) {
{{ var p Props }}
if len(props) > 0 {
{{ p = props[0] }}
}
if p.Type == "" {
{{ p.Type = TypeButton }}
}
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={ string(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 Props) variantClasses() string {
switch b.Variant {
case VariantDestructive:
return "bg-destructive text-destructive-foreground hover:bg-destructive/90"
case VariantOutline:
return "border border-input bg-background hover:bg-accent hover:text-accent-foreground"
case VariantSecondary:
return "bg-secondary text-secondary-foreground hover:bg-secondary/80"
case VariantGhost:
return "hover:bg-accent hover:text-accent-foreground"
case VariantLink:
return "text-primary underline-offset-4 hover:underline"
default:
return "bg-primary text-primary-foreground hover:bg-primary/90"
}
}
func (b Props) sizeClasses() string {
switch b.Size {
case SizeIcon:
return "h-10 w-10"
default:
return "h-10 px-4 py-2 rounded-md"
}
}
func (b Props) modifierClasses() string {
classes := []string{}
if b.FullWidth {
classes = append(classes, "w-full")
}
return strings.Join(classes, " ")
}
Update the import paths to match your project setup.
Primary
package showcase
import "github.com/axzilla/templui/internal/components/button"
templ ButtonPrimary() {
@button.Button() {
Primary
}
}
Secondary
package showcase
import "github.com/axzilla/templui/internal/components/button"
templ ButtonSecondary() {
@button.Button(button.Props{
Variant: button.VariantSecondary,
}) {
Secondary
}
}
Destructive
package showcase
import "github.com/axzilla/templui/internal/components/button"
templ ButtonDestructive() {
@button.Button(button.Props{
Variant: button.VariantDestructive,
}) {
Destructive
}
}
Outline
package showcase
import "github.com/axzilla/templui/internal/components/button"
templ ButtonOutline() {
@button.Button(button.Props{
Variant: button.VariantOutline,
}) {
Outline
}
}
Ghost
package showcase
import "github.com/axzilla/templui/internal/components/button"
templ ButtonGhost() {
@button.Button(button.Props{
Variant: button.VariantGhost,
}) {
Ghost
}
}
Link
package showcase
import "github.com/axzilla/templui/internal/components/button"
templ ButtonLink() {
@button.Button(button.Props{
Variant: button.VariantLink,
}) {
Link
}
}
Icon
package showcase
import (
"github.com/axzilla/templui/internal/components/button"
"github.com/axzilla/templui/internal/components/icon"
)
templ ButtonIcon() {
@button.Button(button.Props{
Size: button.SizeIcon,
Variant: button.VariantOutline,
}) {
@icon.ChevronRight(icon.Props{Size: 16})
}
}
With Icon
package showcase
import (
"github.com/axzilla/templui/internal/components/button"
"github.com/axzilla/templui/internal/components/icon"
)
templ ButtonWithIcon() {
@button.Button(button.Props{
Class: "flex gap-2 items-center",
}) {
@icon.Mail(icon.Props{Size: 16})
Login with Email
}
}
Loading
package showcase
import (
"github.com/axzilla/templui/internal/components/button"
"github.com/axzilla/templui/internal/components/spinner"
)
templ ButtonLoading() {
@button.Button(button.Props{
Disabled: true,
Class: "flex items-center gap-2",
}) {
@spinner.Spinner(spinner.Props{
Size: spinner.SizeSm,
Color: "text-primary-foreground",
})
Please wait
}
}
HTMX Loading (5s)
package showcase
import (
"github.com/axzilla/templui/internal/components/button"
"github.com/axzilla/templui/internal/components/spinner"
)
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"
>
@button.Button(button.Props{
Type: button.TypeSubmit,
Class: "flex items-center gap-2",
}) {
<span id="spinner" class="htmx-indicator hidden [&.htmx-request]:inline-flex">
@spinner.Spinner(spinner.Props{
Size: spinner.SizeSm,
Color: "text-primary-foreground",
})
</span>
Submit
}
</form>
<div id="toast-container"></div>
</div>
}