Gesso
Data display

Card

A raised surface with header, content, and footer slots, and a metric layout.

Card is a raised surface that groups one thing: a summary, a metric, or a short form with its action. It is a set of parts, CardHeader, CardTitle, CardDescription, CardContent, and CardFooter, and it has two weights, default and elevated. Its fill is the look's raised paper, so it repaints with the look, and its corners follow the look's radius.

Default

Surface, border, and ink from the chrome tier.

One elevation step, cast in the tinted shadow ink.

Elevated

Raised paper, stronger border, larger radius, shadow-lg.

For pulled-forward, hero-level surfaces.

Usage

import { Button } from '@/components/ui/button';
import {
  Card,
  CardContent,
  CardDescription,
  CardFooter,
  CardHeader,
  CardTitle,
} from '@/components/ui/card';

<Card>
  <CardHeader>
    <CardTitle>Invite your team</CardTitle>
    <CardDescription>Teammates can edit the same projects.</CardDescription>
  </CardHeader>
  <CardContent>Anyone with the link can join.</CardContent>
  <CardFooter>
    <Button>Copy link</Button>
  </CardFooter>
</Card>

The parts are plain elements with padding, so use as many as the content needs. CardHeader has 24px of padding and a 6px gap between its children, and CardContent and CardFooter have 24px at the sides and bottom and none at the top, so they sit under the header without a doubled gap. CardTitle is an <h3> in text-2xl unless as picks another level, and CardDescription is a <p> in muted text-sm.

Default or elevated

default is the page's own raised fill with the default border and shadow-sm, so a card reads as a section of the page. elevated keeps the same fill and border and adds a larger radius, and shadow-lg, for a surface that is pulled forward, like a hero panel. It also clips its overflow, so an image or a header band that runs to the edge follows the rounded corners.

Card's fill is the same step as the page's and the popover's, so a menu opened from a card is the same color as the card and separates by its strong border and shadow.

Metric cards

CardHeaderRow puts a label and a control on one line, spaced to the two ends. CardMetric sets its children as a 40px number, with an optional label in muted text beside it, and CardSubtext spreads a muted line of supporting values. They are layouts for a number and its context and add no color, so a trend or a status color is yours to add.

Open issues

48this week
12 closed4 blocked
<Card>
  <CardHeader>
    <CardHeaderRow>
      <CardDescription>Open issues</CardDescription>
      <Button size="sm" variant="ghost">View</Button>
    </CardHeaderRow>
    <CardMetric label="this week">48</CardMetric>
  </CardHeader>
  <CardContent>
    <CardSubtext>
      <span>12 closed</span>
      <span>4 blocked</span>
    </CardSubtext>
  </CardContent>
</Card>

Props

Card takes every <div> attribute, plus this.

PropTypeDefaultWhat it does
variant"default" | "elevated""default"default is the fill with a light border and shadow-sm. elevated adds a larger radius, shadow-lg, and clipped overflow.

CardHeader, CardHeaderRow, CardContent, CardSubtext, and CardFooter take every <div> attribute, CardTitle takes every heading attribute plus as, from "h1" to "h6", and CardDescription takes every <p> attribute. CardMetric takes every <div> attribute plus label, a ReactNode shown beside the number. cardVariants({ variant }) returns the classes, for styling something that is not a Card.

Accessibility

  • A Card is a plain <div> with no role and no landmark, and it takes no focus. A screen reader reads its text in order, and its edge is a visual grouping only. When a card is a region a user should be able to jump to, pass role="region" and an aria-labelledby that points at the title.
  • CardTitle is an <h3> by default, which is right under an <h2>. Set as to the level that fits the page's outline anywhere else.
  • A Card is not interactive. For a card that opens something and moves on hover and focus, use Interactive card. If you stay with Card, put a link or a button inside it, and stretch the link with a ::after pseudo-element if the whole card should be the target, so the card has one tab stop and one name.
  • The edge comes from a border and a shadow together. Forced colors drops shadows and keeps borders, so a default or elevated card keeps its outline in Windows high contrast.
  • CardMetric is a number in a <span>, so a screen reader reads "48" without saying what it counts. Keep the label in the same line, as in the demo, and say what the number is in text.
  • Card has no motion, and no color carries meaning. The contrast of text-fg-muted on the raised paper is not checked here.

When to use something else

  • Section for a titled block of a page that does not need a surface. A Section is a labelled <section> with a heading, a description, and header actions, and it draws no fill or border, so use it for the run of blocks on a report page and put Cards inside it when a block needs a frame.
  • Interactive card when the card itself opens something, stacked or side by side, and should move on hover and focus.
  • Item for a single row, with media, a title, a description, and actions. A Card is for a group of content, and an Item is one line of a list.
  • Stat strip for a row of metrics that read together, instead of one Card per number.
  • Dialog or Popover when the surface floats above the page. Card sits in the flow.

Install

shadcn add @gesso/card

On this page