Skip to main content
BM

Card

A surface for grouped content that can link somewhere as a whole.

View source on GitHub

Design tokens

Every color, size and motion value on this site, in light and dark.
CardExample.tsx
import { Badge } from "@/components/Badge";
import { Card } from "@/components/Card";
import { Stack } from "@/components/Stack";

export function CardExample() {
  return (
    <Card
      heading="Design tokens"
      headingLevel={2}
      href="/design-system/tokens"
      footer={
        <Stack as="ul" direction="horizontal" gap="xs" aria-label="Formats">
          <Badge as="li">DTCG JSON</Badge>
          <Badge as="li">CSS</Badge>
        </Stack>
      }
    >
      Every color, size and motion value on this site, in light and dark.
    </Card>
  );
}

Examples

Variants

Raised

A raised surface with a soft shadow.

Outlined

A strong outline, with no fill or shadow.

Flat

A sunken fill, with no outline or shadow.

Glass

Translucent and blurred, over a varied backdrop.

Parts

Static hosting

S3 and CloudFront, deployed from GitHub Actions.

With media

Color tokens

Decorative media, hidden from assistive technology.

Lower Falls

A tall waterfall pours between yellow and rust canyon walls into a green river, framed by pines under a blue sky.
A meaningful image, with alt text.

Linked, with a nested control

Design tokens

Every color, size and motion value, with light and dark themes.

Footers line up

  • Contact form

    Sends me a message.
  • View counter

    Counts visits to each page. Its backend comes later.
  • Component library

    Built on design tokens. Every component is keyboard accessible. Each one has its own section here.

Subgrid

  • Contact form

    Sends me a message.
  • View counter, with a count for every page

    Counts visits to each page. Its backend comes later.
  • Component library

    Built on design tokens. Every component is keyboard accessible. Each one has its own section here.

Any heading level

Project notes

Announced as: “Project notes, heading level 4”

Release notes

Announced as: “Release notes, heading level 5”

Heading look

Featured project

A larger heading, with h3's look.

Case study

A kicker-style heading, with the label look.

Customized with component tokens

Accent outline

An accent border and tighter padding, set through Card's component tokens.
CSS
.accentCard {
  --component-card-raised-border: var(--color-accent-border);
  --component-card-padding: var(--space-inset-md);
}

Props

Any native prop not listed here goes to the root element unchanged.

subgrid works only when the Card is a direct child of a Grid. For several footer items, use a horizontal Stack. Glass needs a varied backdrop behind it. On a link card, aria-current goes to its heading link. Media is shown first but comes after the heading in the DOM.

Card props
PropTypeDefaultDescription
as"article" | "section" | "div" | "li""article"The root element.
headingReactNode—The card's title. Required when href is set.
headingLevel2 | 3 | 4 | 5 | 63Fits the card into the page's heading outline. The look comes from headingVariant.
headingVariant"display" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "lead" | "body" | "small" | "label" | "code" | "inherit""h4"The heading's Typography look, the same at every heading level, except "inherit" and "code", which keep the plain heading's size for its level.
variant"raised" | "outlined" | "flat" | "glass""raised"Surface look, each from its own component tokens.
footerReactNode—Bottom part, at the card's bottom edge.
subgridbooleanfalseIn a Grid, parts line up across the row.
hrefstring—Makes the heading the card's link, and the whole card clickable.
newTabbooleanfalseWith href: open in a new tab.
mediaReactNode—A picture or preview, full-bleed across the top. After the heading in the DOM.

Component tokens

Card component tokens
TokenCopyDescriptionAliasesLightDarkPreview
--component-card-border-widthCard outline width, in every variant.effect.border.width2pxfrom effect.line.22pxfrom effect.line.2
--component-card-radiusCard corners.radius.surface4pxfrom radius.44pxfrom radius.4
--component-card-paddingPadding inside the card.space.inset.lg1.5remfrom space.61.5remfrom space.6
--component-card-gapSpace between the heading, body and footer.space.stack.sm0.5remfrom space.20.5remfrom space.2
--component-card-heading-colorHeading text.color.text.default#17202bfrom color.gray.900#fffffffrom color.gray.0
--component-card-body-colorBody and footer text.color.text.muted#455464from color.gray.700#e6ecf3from color.slate.100
--component-card-media-borderDivider between the media and the rest of the card, in every variant.color.border.default#adbac8from color.gray.300#63676ffrom color.slate.500
--component-card-transition-durationDuration of a link card's hover change (0ms under reduced motion).motion.duration.fast150msfrom motion.time.150Reduced motion: 0ms150msfrom motion.time.150No preview
--component-card-transition-easingEasing of a link card's hover change.motion.easing.standardcubic-bezier(0.4, 0, 0.2, 1)from motion.curve.in-outcubic-bezier(0.4, 0, 0.2, 1)from motion.curve.in-outNo preview
--component-card-raised-backgroundRaised card (the default) surface.color.surface.raised#fffffffrom color.gray.0#18202efrom color.slate.900
--component-card-raised-borderRaised card (the default) outline.color.border.subtle#e5dccbfrom color.sand.200#272f3ffrom color.slate.800
--component-card-raised-elevationRaised card (the default) shadow.effect.elevation.raised0px 1px 2px 0px rgb(0% 0% 0% / 0.08)from effect.shadow.sm0px 1px 2px 0px rgb(0% 0% 0% / 0.3)from effect.shadow.sm-dark
--component-card-raised-background-hoverRaised card (the default) surface while its link is hovered.color.surface.sunken#f2ede2from color.sand.100#060a13from color.slate.1000
--component-card-raised-border-hoverRaised card (the default) outline while its link is hovered.color.border.strong#6d7e90from color.gray.500#818b9efrom color.slate.400
--component-card-outlined-backgroundOutlined card surface.color.fill.nonergba(0, 0, 0, 0)from color.overlay.transparentrgba(0, 0, 0, 0)from color.overlay.transparent
--component-card-outlined-borderOutlined card outline.color.border.strong#6d7e90from color.gray.500#818b9efrom color.slate.400
--component-card-outlined-elevationOutlined card shadow.effect.elevation.none0px 0px 0px 0px rgb(0% 0% 0% / 0)from effect.shadow.none0px 0px 0px 0px rgb(0% 0% 0% / 0)from effect.shadow.none
--component-card-outlined-background-hoverOutlined card surface while its link is hovered.color.surface.sunken#f2ede2from color.sand.100#060a13from color.slate.1000
--component-card-outlined-border-hoverOutlined card outline while its link is hovered.color.border.strong#6d7e90from color.gray.500#818b9efrom color.slate.400
--component-card-flat-backgroundFlat card surface.color.surface.sunken#f2ede2from color.sand.100#060a13from color.slate.1000
--component-card-flat-borderFlat card outline.color.fill.nonergba(0, 0, 0, 0)from color.overlay.transparentrgba(0, 0, 0, 0)from color.overlay.transparent
--component-card-flat-elevationFlat card shadow.effect.elevation.none0px 0px 0px 0px rgb(0% 0% 0% / 0)from effect.shadow.none0px 0px 0px 0px rgb(0% 0% 0% / 0)from effect.shadow.none
--component-card-flat-background-hoverFlat card surface while its link is hovered.color.surface.sunken#f2ede2from color.sand.100#060a13from color.slate.1000
--component-card-flat-border-hoverFlat card outline while its link is hovered.color.border.strong#6d7e90from color.gray.500#818b9efrom color.slate.400
--component-card-glass-backgroundGlass card surface.color.surface.glass-sheerrgba(255, 255, 255, 0.2)from color.overlay.white-20rgba(255, 255, 255, 0.08)from color.overlay.white-8
--component-card-glass-borderGlass card outline.color.border.subtle#e5dccbfrom color.sand.200#272f3ffrom color.slate.800
--component-card-glass-elevationGlass card shadow.effect.elevation.raised0px 1px 2px 0px rgb(0% 0% 0% / 0.08)from effect.shadow.sm0px 1px 2px 0px rgb(0% 0% 0% / 0.3)from effect.shadow.sm-dark
--component-card-glass-background-hoverGlass card surface while its link is hovered.color.surface.glass-sheerrgba(255, 255, 255, 0.2)from color.overlay.white-20rgba(255, 255, 255, 0.08)from color.overlay.white-8
--component-card-glass-border-hoverGlass card outline while its link is hovered.color.border.strong#6d7e90from color.gray.500#818b9efrom color.slate.400
--component-card-glass-highlightGlass card's lit top and left edges, drawn inside the outline.color.border.glass-highlightrgba(255, 255, 255, 0.8)from color.overlay.white-80rgba(255, 255, 255, 0.2)from color.overlay.white-20
--component-card-glass-backdrop-blurBlur behind a glass card.effect.backdrop.glass-sheer6pxfrom effect.blur-radius.66pxfrom effect.blur-radius.6
--component-card-glass-background-opaqueGlass card surface, at rest and on hover, under reduced transparency and in custom themes.color.surface.raised#fffffffrom color.gray.0#18202efrom color.slate.900
--component-card-focus-ring-colorFocus indicator drawn around a link card while its link has focus.color.focus.ring#005f7bfrom color.cyan.700#54d8f4from color.cyan.300

Accessibility

  • An article by default, or section, div or li.
  • A link card has one link: its heading, named by the heading text alone (plus “, opens in new tab” with newTab).
  • The whole surface is clickable for pointers; nested controls keep their own clicks and focus.
  • A link card is never marked aria-current automatically, even on the page it links to. A caller's aria-current goes to its heading link.
  • The heading's look comes from headingVariant and is the same at every level (except with inherit or code), so choose headingLevel by the page outline.
  • Text inside a link card can't be selected, because the link's overlay covers it.
  • The hover look shows only where a click follows the link: not over nested controls, and not on touch screens.
  • Media is shown above the heading but read after it, so the heading always comes first.
  • Card doesn't hide media: mark decorative media aria-hidden, and make a decorative preview of controls inert too. Give a meaningful image alt text.
  • A control in media is shown above the heading but focused after the heading link. Keep it inset from the media's edges by the focus ring's width plus offset, or its ring is clipped.
  • Glass turns opaque when reduced transparency is requested, and in custom themes: only the built-in themes' glass is reviewed over the sphere.
  • Backdrops, for text contrast: raised and flat work on any surface. Outlined is transparent, so use it only on surface.base, raised or sunken. Glass needs a varied backdrop made only of those surfaces, or the dot sphere behind Home and the 404, where glass panels carry text over the dots.
  • A link card's focus ring is drawn on the backdrop around the card, so keep link cards of every variant off action.background: there the ring is the same color in light, and nearly so in dark.
Card keyboard
KeyAction
TabFocuses the heading link (the ring surrounds the card), then any controls inside.
EnterFollows the card's link.