UI.MD

Card

A container with header, content, and footer sections. Includes dashboard and metric card variants.

Installation

$
npx shadcn@latest add https://ui.mattdowney.com/r/card.json

Usage

import {
  Card, CardHeader, CardTitle, CardDescription, CardAction,
  CardContent, CardFooter, CardRows, CardRow, CardTableHeader,
  CardTableBody, DashboardCardHeader, MetricCardValue,
} from "@/components/ui/card"

Examples

Default

Header, content, and footer are each optional. This one skips CardContent and lets the description carry the body, which is the shape a short confirmation card wants.

Notifications
Choose which notifications you'd like to receive and how they're delivered.

With Header Border

Add border-b to CardHeader to separate the header from content.

Notifications

Choose which notifications you'd like to receive and how they're delivered.

With Footer Border

Add border-t to CardFooter to close the card off with a divider. It supplies its own 20px above the actions as soon as it is bordered, matching the 20px already below them, so there is no pt-* to remember.

Notifications
Choose which notifications you'd like to receive and how they're delivered.

With Form

A form inside a card. Three relationships, three rungs: field between the fields, label from a label to its control, and a reopened top gap, since CardContent hugs a borderless header at 8px and a form needs its own room.

Create project
Deploy your new project in one click.

With Action

CardAction places a control in the top-right of the header. The body is CardRows + CardRow rather than a hand-rolled stack: a member list is a row list, so each row owns its padding and hairline and there is no inter-row gap to guess.

Team Members
Manage your team and permissions.
JD

Jane Doe

jane@example.com

Admin
AS

Alex Smith

alex@example.com

Member

With Rows

CardRow creates a bordered list layout for settings or navigation.

Settings
Manage your account preferences.

Notifications

Push and email alerts

Security

Password and 2FA

Language

English (US)

Compact Header

DashboardCardHeader + MetricCardValue for data display cards.

Weekly Steps
47,291
Goal: 50,000 steps2709 to go

Header Action Alignment

Action seating, default flush. A Badge, count, or caption puts its own edge on the 16px inset, level with the title. An icon Button or Kebab carries ~6px of hit-area chrome past its glyph, so it needs actionInset="icon" to seat the glyph there; using it on a bare Badge pulls the count 6px too tight.

Captures15
NewestToday
Oldest5d ago
Weekly Steps
Today8,120
Goal10,000

Table Header

CardTableHeader adds column labels that align with grid rows below.

api-serverHealthy99.9%
web-appHealthy99.7%
workerDegraded97.2%

Expandable

Reveal detail rows with a smooth disclosure. The summary stays put and the toggle lives in the header (neither moves), while the rows expand via Collapsible - a measured height animation that eases open and closed. The card's height just follows the Collapsible, so there's no snap or layout shift.

Order summary
1 item · ships in 2-3 days
Subtotal$48.00

Tabbed Filter

A card whose list is filtered by tabs. Keep the tabs out of DashboardCardHeader: its band is sized for one 32px icon action, so a strip crammed in there sits off-center. The header takes the title and one action, the tabs get their own region below, and a border-t closes them off from the list.

Activity
Deploy to production succeededDeploy · 1h ago
Julik requested changes on #128Review · 3h ago
Andrew commented on RegistryComment · 2m ago

Dotgrid

Set variant="dotgrid" to fill the card with a faint dot-grid canvas. The dots paint behind the content, so children sit on top of the staging surface. Used for positioning and placement demos.

Canvas
A dot-grid staging surface for positioning and placement demos.
Content sits on the canvas

API Reference

PropTypeDefaultDescription
variantCard"default" | "dotgrid""default"Visual treatment. dotgrid fills the card with a faint dot-grid canvas that paints behind the content, a staging surface for positioning and placement demos.
animateHeightCardbooleanfalseSmoothly animates the card's own height when its content size changes. Opt-in; leave off when a child already animates its own height (e.g. an inner Collapsible).
title*DashboardCardHeaderstring-Header label, truncated when it overflows.
actionDashboardCardHeaderReact.ReactNode-Optional control rendered on the right side of the header.
actionInsetDashboardCardHeader"icon" | "flush""flush"How the action seats against the right edge. flush (default) puts the action's own box edge on the content inset, so a Badge, count, or caption aligns with the title. icon outdents 6px for an action whose box extends past what you see (an icon Button or Kebab's transparent hit area, a ghost text button's padding), seating the glyph on the inset instead. The default is flush because a badge dropped in unadorned must look right with no flag; the button case declares its own chrome compensation.
linkDashboardCardHeader{ label: string; onClick: () => void }-Subtle text-button link on the right of the header; ignored when action is set.
insetDashboardCardHeader"default" | "loose""default"Side padding, which must match the body's below it. default (16px) is the row tier and fits most cards. loose (24px) is the prose tier, for a card whose body is paragraphs rather than rows, where 16px reads thin once the card is wide. Set the body to match in the same edit: the header and the content share one left edge, so moving either alone puts the title 8px inboard of every line beneath it.
value*MetricCardValueReact.ReactNode-The large metric value.
goal*MetricCardValueReact.ReactNode-Goal line rendered under the value.
unitMetricCardValuestring-Unit suffix appended to the goal line.
deltaMetricCardValue{ value: number; label?: string }-Progress remainder line: positive values render label (default {value} to go), zero or below renders Goal reached!.
childrenMetricCardValueReact.ReactNode-Optional inline controls rendered beside the value (e.g. +/- buttons).
columns*CardTableHeaderstring[]-Column labels for the header row.
gridClassName*CardTableHeaderstring-Grid classes matching the body rows, e.g. grid-cols-[10rem_1fr_5rem].