Radio Card
Selectable card component that uses radio buttons for single-option selection.
TailwindCSS
package showcase
import (
"github.com/axzilla/templui/internal/components/icon"
"github.com/axzilla/templui/internal/components/radiocard"
)
templ RadioCardDefault() {
<div class="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
@radiocard.RadioCard(radiocard.Props{
ID: "comp-plan-basic",
Name: "comp-plan",
Value: "basic",
}) {
@radiocard.Header() {
<div class="flex items-center gap-2">
@icon.Package(icon.Props{Size: 20})
<h3>Basic Plan</h3>
</div>
}
@radiocard.Description() {
Essential features for individuals and small teams
}
@radiocard.Footer() {
@radioCardPriceFooter("$5.99")
}
}
@radiocard.RadioCard(radiocard.Props{
ID: "comp-plan-pro",
Name: "comp-plan",
Value: "pro",
}) {
@radiocard.Header() {
<div class="flex items-center gap-2">
@icon.Star(icon.Props{Size: 20})
<h3>Pro Plan</h3>
</div>
}
@radiocard.Description() {
Enhanced capabilities for growing businesses.
}
@radiocard.Footer() {
@radioCardPriceFooter("$14.99")
}
}
@radiocard.RadioCard(radiocard.Props{
ID: "comp-plan-enterprise",
Name: "comp-plan",
Value: "enterprise",
Disabled: true,
}) {
@radiocard.Header() {
<div class="flex items-center gap-2">
@icon.Building(icon.Props{Size: 20})
<h3>Enterprise Plan</h3>
</div>
}
@radiocard.Description() {
Advanced features for large organizations
}
@radiocard.Footer() {
@radioCardPriceFooter("$29.99")
}
}
</div>
}
templ radioCardPriceFooter(price string) {
<div class="flex justify-between items-center border-t border-border pt-2 mt-2 text-sm">
<span class="text-muted-foreground">Price</span>
<span class="font-medium">{ price }</span>
</div>
}
Installation
templui add radiocard
Copy and paste the following code into your project:
package radiocard import "github.com/axzilla/templui/internal/utils" type Props struct { ID string Class string Attributes templ.Attributes Name string Value string Checked bool Disabled bool Required bool } type HeaderProps struct { ID string Class string Attributes templ.Attributes } type DescriptionProps struct { ID string Class string Attributes templ.Attributes } type FooterProps struct { ID string Class string Attributes templ.Attributes } templ RadioCard(props ...Props) { {{ var p Props }} if len(props) > 0 { {{ p = props[0] }} } if p.ID == "" { {{ p.ID = utils.RandomID() }} } <div id={ p.ID + "-container" } class={ utils.TwMerge( "relative", utils.If(p.Disabled, "opacity-60"), p.Class, ), } { p.Attributes... } > <input type="radio" id={ p.ID } if p.Name != "" { name={ p.Name } } if p.Value != "" { value={ p.Value } } checked?={ p.Checked } disabled?={ p.Disabled } required?={ p.Required } class="peer sr-only" /> <label for={ p.ID } class={ utils.TwMerge( "block w-full rounded-lg border overflow-hidden h-full", "bg-card text-card-foreground p-4 flex flex-col", "cursor-pointer", "hover:border-primary/50", "peer-checked:ring-1 peer-checked:ring-primary peer-checked:border-primary", utils.If(p.Disabled, "cursor-not-allowed"), "transition-all duration-200", p.Class, ), } { p.Attributes... } > { children... } </label> </div> } templ Header(props ...HeaderProps) { {{ var p HeaderProps }} if len(props) > 0 { {{ p = props[0] }} } <div if p.ID != "" { id={ p.ID } } class={ utils.TwMerge("flex items-center justify-between mb-2", p.Class) } { p.Attributes... } > { children... } </div> } templ Description(props ...DescriptionProps) { {{ var p DescriptionProps }} if len(props) > 0 { {{ p = props[0] }} } <p if p.ID != "" { id={ p.ID } } class={ utils.TwMerge("text-sm text-muted-foreground", p.Class) } { p.Attributes... } > { children... } </p> } templ Footer(props ...FooterProps) { {{ var p FooterProps }} if len(props) > 0 { {{ p = props[0] }} } <div if p.ID != "" { id={ p.ID } } class={ utils.TwMerge("mt-auto pt-4 w-full", p.Class) } { p.Attributes... } > { children... } </div> }
Update the import paths to match your project setup.