Experience System
Components

Card

Bordered surface for grouping related content, metadata, and actions.

Card
A bordered surface for grouped content and actions.
Use header, content, and footer regions to structure the layout.

Installation

The components are exported from @by/experience-system. Add the package with your package manager:

pnpm add @by/experience-system

In this monorepo, depend on the workspace package (for example via workspace:* or your catalog) so imports resolve to packages/experience-system.

Composition

Use the following composition to build a Card:

Card
├── CardHeader
│   ├── CardTitle
│   ├── CardDescription (optional)
│   └── CardAction (optional)
├── CardContent (optional)
└── CardFooter (optional)

CardHeader uses a @container/card-header grid so CardAction aligns to the top trailing edge when present. CardTitle and CardDescription are plain div elements (not headings by default)—choose heading levels in the surrounding page if needed.

Usage

import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from '@by/experience-system';

Card and its parts are client components ('use client'). Use them inside a Client Component or a dynamic import when using the Next.js App Router.

<Card className="max-w-sm">
  <CardHeader>
    <CardTitle>Title</CardTitle>
    <CardDescription>Supporting text.</CardDescription>
  </CardHeader>
  <CardContent>Body content.</CardContent>
</Card>

Examples

Overview

Basic header and content.

Card
A bordered surface for grouped content and actions.
Use header, content, and footer regions to structure the layout.

Form layout

CardAction in the header for a secondary control, CardFooter for primary actions.

Login to your account
Enter your email below to login to your account

Elevation

Shadow utilities on Card for depth (shadow-sm through shadow-xl).

inset-shadow-xs · shadow-none
className="shadow-none inset-shadow-xs"
Use this elevation for recessed inputs and editors
shadow-none
className="shadow-none"
Use this elevation for flat non-elevated cards
shadow-sm
className="shadow-sm"
Use this elevation for dashboard cards
shadow-md
className="shadow-md"
Use this elevation for interactive elevated cards in hovered or activated states
shadow-lg
className="shadow-lg"
Use this elevation for popovers and floating cards
shadow-xl
className="shadow-xl"
Use this elevation for drawers or FABs

Interactive patterns

Link-wrapped card, selectable cards, and RadioGroup card options (focus rings on the interactive wrapper).

Clickable card (link)

Full card is a link: interactive cards have stronger outline than regular cards, use `border-neutral-alpha-6` and `border-neutral-alpha-8` for normal and hovered states respectively.

Open product tour
Learn key workflows in about two minutes.
Uses a wrapping <a> with group-hover / group-focus-visible on the card.

Selectable cards

Click a card to select it; selection uses a higher elevation than idle cards.
Selectable cards have stronger outline than regular cards, use `border-neutral-alpha-6` and `border-neutral-alpha-8` for normal and hovered states respectively.

Radio cards

Use RadioGroup with Radio at the start of each card; wrap the card in Label so the whole surface toggles the option. Only one card can be selected at a time.

API Reference

Subsection titles name the exports from @by/experience-system. These are layout div components (not Radix primitives).

Card

Data attributeValues
data-slotcard

Also accepts standard div attributes.

CardHeader

Data attributeValues
data-slotcard-header

Also accepts standard div attributes.

CardTitle

Data attributeValues
data-slotcard-title

Also accepts standard div attributes.

CardDescription

Data attributeValues
data-slotcard-description

Also accepts standard div attributes.

CardAction

Trailing header actions; participates in the header grid when data-slot="card-action" is present on this node.

Data attributeValues
data-slotcard-action

Also accepts standard div attributes.

CardContent

Data attributeValues
data-slotcard-content

Also accepts standard div attributes.

CardFooter

Data attributeValues
data-slotcard-footer

Also accepts standard div attributes.

Accessibility

Prefer a single primary interactive element per card (one a or button wrapping the card, or explicit buttons inside). If the whole card is clickable, put the focus ring on the wrapper and avoid nested tab stops. For radio-style cards, use RadioGroup + Radio with a Label wrapping the card so the control name matches the visible title. See MDN — Cards for generic container semantics and your product pattern library for card-specific guidance.

Source in the repo: packages/experience-system/src/components/Card/Card.tsx. Agent-oriented contracts: packages/experience-system/src/components/Card/Card.instructions.md.