Skip to content
Gx
GitHub

Card

A bordered surface for grouped content.

<card.Card title="Card title" description="A short description.">
  <:footer>Footer</:footer>
  Card body.
</card.Card>

Installation

Run the command in the app module.

Terminal
gx add card

The command also installs button.

The command writes these files.

File Path in the app
Card.gx ui/card/Card.gx
Card.fixtures.go ui/card/Card.fixtures.go

Install button first.

Copy each file to its path in the app. Change each import of a registry package to the path of that package in the app.

ui/card/Card.gx
package card

props {
  // Title is the heading of the card. An empty value renders no heading.
  Title       string = ""
  // Description is the text below the title. An empty value renders no description.
  Description string = ""
  // Action is a control shown at the top right of the card header. A nil value renders no action.
  Action      gx.Node = nil
  // Footer is the content of the card footer. A nil value renders no footer.
  Footer      gx.Node = nil
  // Class adds classes to the root element.
  Class       string = ""
  // Children is the content of the card.
  Children    gx.Node = nil
  // Attrs adds HTML attributes to the root element.
  Attrs       gx.Attrs = nil
}

<div data-slot="card" class={gx.Cx("flex flex-col gap-6 rounded-xl border border-border bg-card py-6 text-card-foreground shadow-sm", p.Class)} {...p.Attrs}>
  if p.Title != "" || p.Description != "" || p.Action != nil {
    <div data-slot="card-header" class="@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6">
      if p.Title != "" {
        <h3 data-slot="card-title" class="leading-none font-semibold">{p.Title}</h3>
      }
      if p.Description != "" {
        <p data-slot="card-description" class="text-sm text-muted-foreground">{p.Description}</p>
      }
      if p.Action != nil {
        <div data-slot="card-action" class="col-start-2 row-span-2 row-start-1 self-start justify-self-end">{p.Action}</div>
      }
    </div>
  }
  if p.Children != nil {
    <div data-slot="card-content" class="px-6">{p.Children}</div>
  }
  if p.Footer != nil {
    <div data-slot="card-footer" class="flex items-center px-6 [.border-t]:pt-6">{p.Footer}</div>
  }
</div>
ui/card/Card.fixtures.go
package card

import (
	"github.com/alternayte/gx"
	"github.com/alternayte/gx/registry/button"
)

var CardFixtures = gx.Fixtures[CardProps]{
	"Full":      {Title: "Card title", Description: "A short description.", Children: gx.Text("Card body."), Footer: gx.Text("Footer")},
	"TitleOnly": {Title: "Title only"},
	"BodyOnly":  {Children: gx.Text("Body only.")},
	"Action": {
		Title:       "Sign in",
		Description: "Enter your email to sign in.",
		Action:      button.Button(button.ButtonProps{Variant: button.Link, Children: gx.Text("Sign up")}),
		Children:    gx.Text("Card body."),
		Footer:      button.Button(button.ButtonProps{Class: "w-full", Children: gx.Text("Continue")}),
	},
}

The theme must define these tokens: --card, --card-foreground, --border, --muted-foreground.

Usage

<card.Card title="Team" description="Manage the members." footer={saveButton}>
  <:action><button.Button variant={button.Link}>Invite</button.Button></:action>
  <p>Card body.</p>
</card.Card>

Title and Description make the header. Action sits at the top right of the header. The children are the content. Footer is the last row.

Examples

Full

<card.Card title="Card title" description="A short description.">
  <:footer>Footer</:footer>
  Card body.
</card.Card>

Title only

<card.Card title="Title only" />

Body only

<card.Card>Body only.</card.Card>

Action

<card.Card title="Sign in" description="Enter your email to sign in.">
  <:action><button.Button variant={button.Link}>Sign up</button.Button></:action>
  <:footer><button.Button class="w-full">Continue</button.Button></:footer>
  Card body.
</card.Card>

API reference

A tag sets a prop by its name with a lower-case first letter: Class is class.

card.Card

Prop Type Default Description
Title string "" Title is the heading of the card. An empty value renders no heading.
Description string "" Description is the text below the title. An empty value renders no description.
Action gx.Node nil Action is a control shown at the top right of the card header. A nil value renders no action.
Footer gx.Node nil Footer is the content of the card footer. A nil value renders no footer.
Class string "" Class adds classes to the root element.
Children gx.Node nil Children is the content of the card.
Attrs gx.Attrs nil Attrs adds HTML attributes to the root element.

Do and do not

Do

  • Use one card for one subject.
  • Put the main action of the card in Footer.

Don't

  • Do not nest a card in a card.
  • Do not use a card for a page layout. Use CSS.

Keyboard

Key Action
None The component is static.