Card
Container for organizing related content and
TailwindCSS
Create Project
Deploy your new project in one-click.
package showcase
import "github.com/axzilla/templui/components"
templ CardDefault() {
<div class="w-full max-w-sm">
@components.Card() {
@components.CardHeader() {
@components.CardTitle() {
Create Project
}
@components.CardDescription() {
Deploy your new project in one-click.
}
}
@components.CardContent() {
<div class="flex flex-col gap-4">
<div class="w-full max-w-sm grid gap-2">
@components.Label(components.LabelProps{
For: "name",
}) {
Name
}
@components.Input(components.InputProps{
ID: "name",
Placeholder: "Enter project name",
})
</div>
<div class="w-full max-w-sm grid gap-2">
@components.Label(components.LabelProps{
For: "service",
}) {
Service
}
@components.Select() {
@components.SelectTrigger(components.SelectTriggerProps{
ID: "service",
}) {
@components.SelectValue(components.SelectValueProps{
Placeholder: "Select",
})
}
@components.SelectContent() {
@components.SelectGroup() {
@components.SelectItem(components.SelectItemProps{
Value: "postgres",
}) {
PostgreSQL
}
@components.SelectItem(components.SelectItemProps{
Value: "mysql",
}) {
MySQL
}
@components.SelectItem(components.SelectItemProps{
Value: "sqlite",
}) {
SQLite
}
}
}
}
</div>
</div>
}
@components.CardFooter(components.CardFooterProps{
Class: "flex justify-between",
}) {
@components.Button(components.ButtonProps{
Variant: components.ButtonVariantSecondary,
}) {
Cancel
}
@components.Button() {
Deploy
}
}
}
</div>
}
package components
import "github.com/axzilla/templui/utils"
type CardMediaPosition string
type CardMediaWidth string
const (
CardMediaTop CardMediaPosition = "top"
CardMediaBottom CardMediaPosition = "bottom"
CardMediaLeft CardMediaPosition = "left"
CardMediaRight CardMediaPosition = "right"
)
const (
CardMediaWidthAuto CardMediaWidth = "auto"
CardMediaWidthFull CardMediaWidth = "full"
CardMediaWidthHalf CardMediaWidth = "half"
CardMediaWidthThird CardMediaWidth = "third"
CardMediaWidthQuarter CardMediaWidth = "quarter"
CardMediaWidthTwoThirds CardMediaWidth = "two-thirds"
CardMediaWidthThreeQuarters CardMediaWidth = "three-quarters"
)
type CardProps struct {
ID string
Class string
Attributes templ.Attributes
}
type CardHeaderProps struct {
ID string
Class string
Attributes templ.Attributes
}
type CardTitleProps struct {
ID string
Class string
Attributes templ.Attributes
}
type CardDescriptionProps struct {
ID string
Class string
Attributes templ.Attributes
}
type CardContentProps struct {
ID string
Class string
Attributes templ.Attributes
}
type CardFooterProps struct {
ID string
Class string
Attributes templ.Attributes
}
type CardHorizontalProps struct {
ID string
Class string
Attributes templ.Attributes
}
type CardMediaProps struct {
ID string
Class string
Attributes templ.Attributes
Src string
Alt string
Position CardMediaPosition
Width CardMediaWidth
AspectRatio AspectRatioVariant
}
templ Card(props ...CardProps) {
{{ var p CardProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<div
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"w-full rounded-lg border bg-card text-card-foreground shadow-xs",
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</div>
}
templ CardHeader(props ...CardHeaderProps) {
{{ var p CardHeaderProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<div
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"flex flex-col space-y-1.5 p-6 pb-0",
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</div>
}
templ CardTitle(props ...CardTitleProps) {
{{ var p CardTitleProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<h3
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"text-lg font-semibold leading-none tracking-tight",
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</h3>
}
templ CardDescription(props ...CardDescriptionProps) {
{{ var p CardDescriptionProps }}
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 CardContent(props ...CardContentProps) {
{{ var p CardContentProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<div
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"p-6",
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</div>
}
templ CardFooter(props ...CardFooterProps) {
{{ var p CardFooterProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<div
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"flex items-center p-6 pt-0",
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</div>
}
templ CardHorizontal(props ...CardHorizontalProps) {
{{ var p CardHorizontalProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<div
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"flex overflow-hidden",
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</div>
}
templ CardMedia(props ...CardMediaProps) {
{{ var p CardMediaProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<div
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"overflow-hidden",
getCardMediaPositionClasses(p.Position, p.Width),
p.Class,
),
}
{ p.Attributes... }
>
@AspectRatio(AspectRatioProps{
ID: p.ID + "-aspect",
Ratio: p.AspectRatio,
Class: "h-full w-full",
}) {
<img
if p.Src != "" {
src={ p.Src }
}
if p.Alt != "" {
alt={ p.Alt }
}
class="h-full w-full object-cover"
/>
}
</div>
}
func getCardMediaPositionClasses(position CardMediaPosition, width CardMediaWidth) string {
var positionClass string
switch position {
case CardMediaTop:
return "w-full rounded-t-lg"
case CardMediaBottom:
return "w-full rounded-b-lg"
case CardMediaLeft:
positionClass = "shrink-0 rounded-l-lg"
case CardMediaRight:
positionClass = "shrink-0 rounded-r-lg"
default:
positionClass = ""
}
if position == CardMediaLeft || position == CardMediaRight {
return positionClass + " " + getWidthClass(width)
}
return positionClass
}
func getWidthClass(width CardMediaWidth) string {
switch width {
case CardMediaWidthFull:
return "w-full"
case CardMediaWidthHalf:
return "w-1/2"
case CardMediaWidthThird:
return "w-1/3"
case CardMediaWidthQuarter:
return "w-1/4"
case CardMediaWidthTwoThirds:
return "w-2/3"
case CardMediaWidthThreeQuarters:
return "w-3/4"
default:
return "w-1/3"
}
}
Usage
@components.Card(components.CardProps{...})
Examples
Image Left

Side Image Card
With left-aligned image
This card demonstrates the left image layout.
package showcase
import "github.com/axzilla/templui/components"
templ CardImageLeft() {
<div class="w-full max-w-sm">
@components.Card() {
@components.CardHorizontal() {
@components.CardMedia(components.CardMediaProps{
ID: "left-media",
Alt: "Left side image",
Position: components.CardMediaLeft,
Width: components.CardMediaWidthThird,
AspectRatio: components.AspectRatioAuto,
Src: "/assets/img/card_placeholder.jpeg",
},
)
<div class="flex flex-col flex-1">
@components.CardHeader() {
@components.CardTitle() {
Side Image Card
}
@components.CardDescription() {
With left-aligned image
}
}
@components.CardContent() {
<p>This card demonstrates the left image layout.</p>
}
</div>
}
}
</div>
}
package components
import "github.com/axzilla/templui/utils"
type CardMediaPosition string
type CardMediaWidth string
const (
CardMediaTop CardMediaPosition = "top"
CardMediaBottom CardMediaPosition = "bottom"
CardMediaLeft CardMediaPosition = "left"
CardMediaRight CardMediaPosition = "right"
)
const (
CardMediaWidthAuto CardMediaWidth = "auto"
CardMediaWidthFull CardMediaWidth = "full"
CardMediaWidthHalf CardMediaWidth = "half"
CardMediaWidthThird CardMediaWidth = "third"
CardMediaWidthQuarter CardMediaWidth = "quarter"
CardMediaWidthTwoThirds CardMediaWidth = "two-thirds"
CardMediaWidthThreeQuarters CardMediaWidth = "three-quarters"
)
type CardProps struct {
ID string
Class string
Attributes templ.Attributes
}
type CardHeaderProps struct {
ID string
Class string
Attributes templ.Attributes
}
type CardTitleProps struct {
ID string
Class string
Attributes templ.Attributes
}
type CardDescriptionProps struct {
ID string
Class string
Attributes templ.Attributes
}
type CardContentProps struct {
ID string
Class string
Attributes templ.Attributes
}
type CardFooterProps struct {
ID string
Class string
Attributes templ.Attributes
}
type CardHorizontalProps struct {
ID string
Class string
Attributes templ.Attributes
}
type CardMediaProps struct {
ID string
Class string
Attributes templ.Attributes
Src string
Alt string
Position CardMediaPosition
Width CardMediaWidth
AspectRatio AspectRatioVariant
}
templ Card(props ...CardProps) {
{{ var p CardProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<div
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"w-full rounded-lg border bg-card text-card-foreground shadow-xs",
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</div>
}
templ CardHeader(props ...CardHeaderProps) {
{{ var p CardHeaderProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<div
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"flex flex-col space-y-1.5 p-6 pb-0",
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</div>
}
templ CardTitle(props ...CardTitleProps) {
{{ var p CardTitleProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<h3
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"text-lg font-semibold leading-none tracking-tight",
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</h3>
}
templ CardDescription(props ...CardDescriptionProps) {
{{ var p CardDescriptionProps }}
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 CardContent(props ...CardContentProps) {
{{ var p CardContentProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<div
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"p-6",
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</div>
}
templ CardFooter(props ...CardFooterProps) {
{{ var p CardFooterProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<div
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"flex items-center p-6 pt-0",
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</div>
}
templ CardHorizontal(props ...CardHorizontalProps) {
{{ var p CardHorizontalProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<div
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"flex overflow-hidden",
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</div>
}
templ CardMedia(props ...CardMediaProps) {
{{ var p CardMediaProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<div
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"overflow-hidden",
getCardMediaPositionClasses(p.Position, p.Width),
p.Class,
),
}
{ p.Attributes... }
>
@AspectRatio(AspectRatioProps{
ID: p.ID + "-aspect",
Ratio: p.AspectRatio,
Class: "h-full w-full",
}) {
<img
if p.Src != "" {
src={ p.Src }
}
if p.Alt != "" {
alt={ p.Alt }
}
class="h-full w-full object-cover"
/>
}
</div>
}
func getCardMediaPositionClasses(position CardMediaPosition, width CardMediaWidth) string {
var positionClass string
switch position {
case CardMediaTop:
return "w-full rounded-t-lg"
case CardMediaBottom:
return "w-full rounded-b-lg"
case CardMediaLeft:
positionClass = "shrink-0 rounded-l-lg"
case CardMediaRight:
positionClass = "shrink-0 rounded-r-lg"
default:
positionClass = ""
}
if position == CardMediaLeft || position == CardMediaRight {
return positionClass + " " + getWidthClass(width)
}
return positionClass
}
func getWidthClass(width CardMediaWidth) string {
switch width {
case CardMediaWidthFull:
return "w-full"
case CardMediaWidthHalf:
return "w-1/2"
case CardMediaWidthThird:
return "w-1/3"
case CardMediaWidthQuarter:
return "w-1/4"
case CardMediaWidthTwoThirds:
return "w-2/3"
case CardMediaWidthThreeQuarters:
return "w-3/4"
default:
return "w-1/3"
}
}
Image Right
Side Image Card
With right-aligned image
This card demonstrates the right image layout.

package showcase
import "github.com/axzilla/templui/components"
templ CardImageRight() {
<div class="w-full max-w-sm">
@components.Card() {
@components.CardHorizontal() {
<div class="flex flex-col flex-1">
@components.CardHeader() {
@components.CardTitle() {
Side Image Card
}
@components.CardDescription() {
With right-aligned image
}
}
@components.CardContent() {
<p>This card demonstrates the right image layout.</p>
}
</div>
@components.CardMedia(components.CardMediaProps{
ID: "right-media",
Alt: "Right side image",
Position: components.CardMediaRight,
Width: components.CardMediaWidthThird,
AspectRatio: components.AspectRatioAuto,
Src: "/assets/img/card_placeholder.jpeg",
},
)
}
}
</div>
}
package components
import "github.com/axzilla/templui/utils"
type CardMediaPosition string
type CardMediaWidth string
const (
CardMediaTop CardMediaPosition = "top"
CardMediaBottom CardMediaPosition = "bottom"
CardMediaLeft CardMediaPosition = "left"
CardMediaRight CardMediaPosition = "right"
)
const (
CardMediaWidthAuto CardMediaWidth = "auto"
CardMediaWidthFull CardMediaWidth = "full"
CardMediaWidthHalf CardMediaWidth = "half"
CardMediaWidthThird CardMediaWidth = "third"
CardMediaWidthQuarter CardMediaWidth = "quarter"
CardMediaWidthTwoThirds CardMediaWidth = "two-thirds"
CardMediaWidthThreeQuarters CardMediaWidth = "three-quarters"
)
type CardProps struct {
ID string
Class string
Attributes templ.Attributes
}
type CardHeaderProps struct {
ID string
Class string
Attributes templ.Attributes
}
type CardTitleProps struct {
ID string
Class string
Attributes templ.Attributes
}
type CardDescriptionProps struct {
ID string
Class string
Attributes templ.Attributes
}
type CardContentProps struct {
ID string
Class string
Attributes templ.Attributes
}
type CardFooterProps struct {
ID string
Class string
Attributes templ.Attributes
}
type CardHorizontalProps struct {
ID string
Class string
Attributes templ.Attributes
}
type CardMediaProps struct {
ID string
Class string
Attributes templ.Attributes
Src string
Alt string
Position CardMediaPosition
Width CardMediaWidth
AspectRatio AspectRatioVariant
}
templ Card(props ...CardProps) {
{{ var p CardProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<div
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"w-full rounded-lg border bg-card text-card-foreground shadow-xs",
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</div>
}
templ CardHeader(props ...CardHeaderProps) {
{{ var p CardHeaderProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<div
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"flex flex-col space-y-1.5 p-6 pb-0",
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</div>
}
templ CardTitle(props ...CardTitleProps) {
{{ var p CardTitleProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<h3
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"text-lg font-semibold leading-none tracking-tight",
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</h3>
}
templ CardDescription(props ...CardDescriptionProps) {
{{ var p CardDescriptionProps }}
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 CardContent(props ...CardContentProps) {
{{ var p CardContentProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<div
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"p-6",
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</div>
}
templ CardFooter(props ...CardFooterProps) {
{{ var p CardFooterProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<div
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"flex items-center p-6 pt-0",
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</div>
}
templ CardHorizontal(props ...CardHorizontalProps) {
{{ var p CardHorizontalProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<div
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"flex overflow-hidden",
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</div>
}
templ CardMedia(props ...CardMediaProps) {
{{ var p CardMediaProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<div
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"overflow-hidden",
getCardMediaPositionClasses(p.Position, p.Width),
p.Class,
),
}
{ p.Attributes... }
>
@AspectRatio(AspectRatioProps{
ID: p.ID + "-aspect",
Ratio: p.AspectRatio,
Class: "h-full w-full",
}) {
<img
if p.Src != "" {
src={ p.Src }
}
if p.Alt != "" {
alt={ p.Alt }
}
class="h-full w-full object-cover"
/>
}
</div>
}
func getCardMediaPositionClasses(position CardMediaPosition, width CardMediaWidth) string {
var positionClass string
switch position {
case CardMediaTop:
return "w-full rounded-t-lg"
case CardMediaBottom:
return "w-full rounded-b-lg"
case CardMediaLeft:
positionClass = "shrink-0 rounded-l-lg"
case CardMediaRight:
positionClass = "shrink-0 rounded-r-lg"
default:
positionClass = ""
}
if position == CardMediaLeft || position == CardMediaRight {
return positionClass + " " + getWidthClass(width)
}
return positionClass
}
func getWidthClass(width CardMediaWidth) string {
switch width {
case CardMediaWidthFull:
return "w-full"
case CardMediaWidthHalf:
return "w-1/2"
case CardMediaWidthThird:
return "w-1/3"
case CardMediaWidthQuarter:
return "w-1/4"
case CardMediaWidthTwoThirds:
return "w-2/3"
case CardMediaWidthThreeQuarters:
return "w-3/4"
default:
return "w-1/3"
}
}
Image Top

Featured Card
With top image
This card shows top image usage.
package showcase
import "github.com/axzilla/templui/components"
templ CardImageTop() {
<div class="w-full max-w-sm">
@components.Card() {
@components.CardMedia(components.CardMediaProps{
ID: "top-media",
Alt: "Card image",
Position: components.CardMediaTop,
AspectRatio: components.AspectRatioVideo,
Src: "/assets/img/card_placeholder.jpeg",
},
)
@components.CardHeader() {
@components.CardTitle() {
Featured Card
}
@components.CardDescription() {
With top image
}
}
@components.CardContent() {
<p>This card shows top image usage.</p>
}
@components.CardFooter() {
@components.Button() {
Learn more
}
}
}
</div>
}
package components
import "github.com/axzilla/templui/utils"
type CardMediaPosition string
type CardMediaWidth string
const (
CardMediaTop CardMediaPosition = "top"
CardMediaBottom CardMediaPosition = "bottom"
CardMediaLeft CardMediaPosition = "left"
CardMediaRight CardMediaPosition = "right"
)
const (
CardMediaWidthAuto CardMediaWidth = "auto"
CardMediaWidthFull CardMediaWidth = "full"
CardMediaWidthHalf CardMediaWidth = "half"
CardMediaWidthThird CardMediaWidth = "third"
CardMediaWidthQuarter CardMediaWidth = "quarter"
CardMediaWidthTwoThirds CardMediaWidth = "two-thirds"
CardMediaWidthThreeQuarters CardMediaWidth = "three-quarters"
)
type CardProps struct {
ID string
Class string
Attributes templ.Attributes
}
type CardHeaderProps struct {
ID string
Class string
Attributes templ.Attributes
}
type CardTitleProps struct {
ID string
Class string
Attributes templ.Attributes
}
type CardDescriptionProps struct {
ID string
Class string
Attributes templ.Attributes
}
type CardContentProps struct {
ID string
Class string
Attributes templ.Attributes
}
type CardFooterProps struct {
ID string
Class string
Attributes templ.Attributes
}
type CardHorizontalProps struct {
ID string
Class string
Attributes templ.Attributes
}
type CardMediaProps struct {
ID string
Class string
Attributes templ.Attributes
Src string
Alt string
Position CardMediaPosition
Width CardMediaWidth
AspectRatio AspectRatioVariant
}
templ Card(props ...CardProps) {
{{ var p CardProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<div
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"w-full rounded-lg border bg-card text-card-foreground shadow-xs",
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</div>
}
templ CardHeader(props ...CardHeaderProps) {
{{ var p CardHeaderProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<div
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"flex flex-col space-y-1.5 p-6 pb-0",
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</div>
}
templ CardTitle(props ...CardTitleProps) {
{{ var p CardTitleProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<h3
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"text-lg font-semibold leading-none tracking-tight",
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</h3>
}
templ CardDescription(props ...CardDescriptionProps) {
{{ var p CardDescriptionProps }}
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 CardContent(props ...CardContentProps) {
{{ var p CardContentProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<div
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"p-6",
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</div>
}
templ CardFooter(props ...CardFooterProps) {
{{ var p CardFooterProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<div
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"flex items-center p-6 pt-0",
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</div>
}
templ CardHorizontal(props ...CardHorizontalProps) {
{{ var p CardHorizontalProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<div
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"flex overflow-hidden",
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</div>
}
templ CardMedia(props ...CardMediaProps) {
{{ var p CardMediaProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<div
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"overflow-hidden",
getCardMediaPositionClasses(p.Position, p.Width),
p.Class,
),
}
{ p.Attributes... }
>
@AspectRatio(AspectRatioProps{
ID: p.ID + "-aspect",
Ratio: p.AspectRatio,
Class: "h-full w-full",
}) {
<img
if p.Src != "" {
src={ p.Src }
}
if p.Alt != "" {
alt={ p.Alt }
}
class="h-full w-full object-cover"
/>
}
</div>
}
func getCardMediaPositionClasses(position CardMediaPosition, width CardMediaWidth) string {
var positionClass string
switch position {
case CardMediaTop:
return "w-full rounded-t-lg"
case CardMediaBottom:
return "w-full rounded-b-lg"
case CardMediaLeft:
positionClass = "shrink-0 rounded-l-lg"
case CardMediaRight:
positionClass = "shrink-0 rounded-r-lg"
default:
positionClass = ""
}
if position == CardMediaLeft || position == CardMediaRight {
return positionClass + " " + getWidthClass(width)
}
return positionClass
}
func getWidthClass(width CardMediaWidth) string {
switch width {
case CardMediaWidthFull:
return "w-full"
case CardMediaWidthHalf:
return "w-1/2"
case CardMediaWidthThird:
return "w-1/3"
case CardMediaWidthQuarter:
return "w-1/4"
case CardMediaWidthTwoThirds:
return "w-2/3"
case CardMediaWidthThreeQuarters:
return "w-3/4"
default:
return "w-1/3"
}
}
Image Bottom
Featured Card
With bottom image
This card shows bottom image usage.

package showcase
import "github.com/axzilla/templui/components"
templ CardImageBottom() {
<div class="w-full max-w-sm">
@components.Card() {
@components.CardHeader() {
@components.CardTitle() {
Featured Card
}
@components.CardDescription() {
With bottom image
}
}
@components.CardContent() {
<p>This card shows bottom image usage.</p>
}
@components.CardFooter() {
@components.Button() {
Learn more
}
}
@components.CardMedia(components.CardMediaProps{
ID: "bottom-media",
Alt: "Card image",
Position: components.CardMediaBottom,
AspectRatio: components.AspectRatioVideo,
Src: "/assets/img/card_placeholder.jpeg",
},
)
}
</div>
}
package components
import "github.com/axzilla/templui/utils"
type CardMediaPosition string
type CardMediaWidth string
const (
CardMediaTop CardMediaPosition = "top"
CardMediaBottom CardMediaPosition = "bottom"
CardMediaLeft CardMediaPosition = "left"
CardMediaRight CardMediaPosition = "right"
)
const (
CardMediaWidthAuto CardMediaWidth = "auto"
CardMediaWidthFull CardMediaWidth = "full"
CardMediaWidthHalf CardMediaWidth = "half"
CardMediaWidthThird CardMediaWidth = "third"
CardMediaWidthQuarter CardMediaWidth = "quarter"
CardMediaWidthTwoThirds CardMediaWidth = "two-thirds"
CardMediaWidthThreeQuarters CardMediaWidth = "three-quarters"
)
type CardProps struct {
ID string
Class string
Attributes templ.Attributes
}
type CardHeaderProps struct {
ID string
Class string
Attributes templ.Attributes
}
type CardTitleProps struct {
ID string
Class string
Attributes templ.Attributes
}
type CardDescriptionProps struct {
ID string
Class string
Attributes templ.Attributes
}
type CardContentProps struct {
ID string
Class string
Attributes templ.Attributes
}
type CardFooterProps struct {
ID string
Class string
Attributes templ.Attributes
}
type CardHorizontalProps struct {
ID string
Class string
Attributes templ.Attributes
}
type CardMediaProps struct {
ID string
Class string
Attributes templ.Attributes
Src string
Alt string
Position CardMediaPosition
Width CardMediaWidth
AspectRatio AspectRatioVariant
}
templ Card(props ...CardProps) {
{{ var p CardProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<div
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"w-full rounded-lg border bg-card text-card-foreground shadow-xs",
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</div>
}
templ CardHeader(props ...CardHeaderProps) {
{{ var p CardHeaderProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<div
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"flex flex-col space-y-1.5 p-6 pb-0",
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</div>
}
templ CardTitle(props ...CardTitleProps) {
{{ var p CardTitleProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<h3
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"text-lg font-semibold leading-none tracking-tight",
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</h3>
}
templ CardDescription(props ...CardDescriptionProps) {
{{ var p CardDescriptionProps }}
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 CardContent(props ...CardContentProps) {
{{ var p CardContentProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<div
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"p-6",
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</div>
}
templ CardFooter(props ...CardFooterProps) {
{{ var p CardFooterProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<div
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"flex items-center p-6 pt-0",
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</div>
}
templ CardHorizontal(props ...CardHorizontalProps) {
{{ var p CardHorizontalProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<div
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"flex overflow-hidden",
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
</div>
}
templ CardMedia(props ...CardMediaProps) {
{{ var p CardMediaProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<div
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"overflow-hidden",
getCardMediaPositionClasses(p.Position, p.Width),
p.Class,
),
}
{ p.Attributes... }
>
@AspectRatio(AspectRatioProps{
ID: p.ID + "-aspect",
Ratio: p.AspectRatio,
Class: "h-full w-full",
}) {
<img
if p.Src != "" {
src={ p.Src }
}
if p.Alt != "" {
alt={ p.Alt }
}
class="h-full w-full object-cover"
/>
}
</div>
}
func getCardMediaPositionClasses(position CardMediaPosition, width CardMediaWidth) string {
var positionClass string
switch position {
case CardMediaTop:
return "w-full rounded-t-lg"
case CardMediaBottom:
return "w-full rounded-b-lg"
case CardMediaLeft:
positionClass = "shrink-0 rounded-l-lg"
case CardMediaRight:
positionClass = "shrink-0 rounded-r-lg"
default:
positionClass = ""
}
if position == CardMediaLeft || position == CardMediaRight {
return positionClass + " " + getWidthClass(width)
}
return positionClass
}
func getWidthClass(width CardMediaWidth) string {
switch width {
case CardMediaWidthFull:
return "w-full"
case CardMediaWidthHalf:
return "w-1/2"
case CardMediaWidthThird:
return "w-1/3"
case CardMediaWidthQuarter:
return "w-1/4"
case CardMediaWidthTwoThirds:
return "w-2/3"
case CardMediaWidthThreeQuarters:
return "w-3/4"
default:
return "w-1/3"
}
}