Card
Media, content, and footer composition for product surfaces.
Examples
Default
Matches the Figma Card anatomy: media, heading + overflow, subtitle, description, badges, and a simple action footer.
Edit the code below — the preview updates live.
Title
Subtitle
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut et massa mi.
Footer layouts
layout maps to Figma footer types: end (Buttons Simple / IconButton), fluid (Buttons Fluid), between (Social).
Fluid actions
Icon action
Social
Without media
Title
Use Card as a content shell when media is optional.
RTL
Wrap the card (or a parent) in dir="rtl" / lang="fa" with Farsi copy. Right-align the demo in the preview (items-start on a full-width RTL flex panel).
عنوان
زیرعنوان
این متن نمونه کارت به زبان فارسی برای بررسی جهت راستبهچپ است.
API Reference
Card
Root surface. Compose with Card.Media, Card.Body, and Card.Footer.
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | Card regions |
className | string | — | Extra class names |
Card.Media
| Prop | Type | Default | Description |
|---|---|---|---|
src | string | — | Image source |
alt | string | empty string | Accessible name; empty when decorative |
aspectRatio | string | 16 / 9 | CSS aspect-ratio |
objectFit | cover / contain / fill / none | cover | Image fit |
Card.Heading
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | Title |
action | ReactNode | — | Trailing overflow control |
as | heading / p / div | h3 | Title element |
Card.Footer
| Prop | Type | Default | Description |
|---|---|---|---|
layout | end / fluid / between | end | Action alignment |
divider | boolean | true | Top hairline |
Also: Card.Body, Card.Subtitle, Card.Description, Card.Badges, Card.Badge, Card.Meta, Card.MetaItem.
Accessibility
WCAG success criteria
| Criterion | Level | How Card supports it | |
|---|---|---|---|
| 1.1.1 Non-text Content | A | Card.Media renders a native <img> with alt (defaults to "" for decorative). Pass a meaningful alt when the image conveys information. | |
| 1.3.1 Info and Relationships | A | Card.Heading uses a real heading (h3 by default via as); subtitle/description are <p>; badges and meta are plain text spans. | |
| 1.3.2 Meaningful Sequence | A | Column flex preserves DOM order (no order reshuffling). Compose media → body → footer so that sequence is the reading order; heading/footer rows follow dir. | |
| 1.4.3 Contrast (Minimum) | AA | Title, subtitle, description, and meta use semantic text tokens on the surface background. Validate on custom Card backgrounds. | |
| 1.4.11 Non-text Contrast | AA | Footer hairline and badge chrome use border / surface tokens. Nested controls (e.g. Button) carry their own non-text contrast. | |
| 2.4.3 Focus Order | A | No focus management or trapping. Tab order is the DOM: typically heading action, then any body controls, then footer. | |
| 2.4.6 Headings and Labels | AA | Card.Heading defaults to h3; set as so the title fits the page outline. | |
| 1.4.1 Use of Color | A | Consumer responsibility — Card.Badge is a single informative style; do not restyle color to carry meaning without descriptive text. | |
| 2.1.1 Keyboard | A | Consumer responsibility — Card is not a widget. Nested controls in action / Card.Footer must be keyboard-operable (Button, links). | |
| 2.4.7 Focus Visible | AA | Card root is not focusable. Nested EDS controls (e.g. Button) provide :focus-visible rings — verify they are not clipped by the card’s overflow: clip. |
Why it matters
Cards package media, titles, and actions into a dense product surface. When the title is a styled div, the image has no alt, or the whole card is wrapped in a link that also contains buttons, keyboard and screen-reader users get an unpredictable tab order, duplicate activation, or a missing outline of the page. EDS Card stays a layout composition — semantics come from real headings, honest image text alternatives, and properly labeled nested controls.
Keyboard
Card itself is not focusable and does not define a widget keyboard model. Interaction belongs to the controls you compose into it.
| Key / action | Behavior |
|---|---|
| ⇥ Tab | Moves through focusable descendants in DOM order (heading action, then body controls, then footer). |
| ⇧ + ⇥ Tab | Reverse focus order through the same descendants. |
| ↵ Enter / Space | Activate the focused nested control (e.g. Button) — not the card surface. |
| ⎋ Esc | No card-level behavior; menus or dialogs you open from action / footer own dismiss. |
Do not make the card root a single giant link when it also contains buttons — that creates nested interactive content and a confusing focus path. Put navigation on one clear control (footer primary, or heading action) instead.
Screen readers & semantics
| Surface | Implementation |
|---|---|
| Root | Plain <div class="eds-card"> — no landmark or role. Add aria-labelledby only if you need a named region for a specific layout. |
Card.Media | Native <img>; alt defaults to "" (decorative). Informative art needs a concise alt that does not repeat the heading verbatim. |
Card.Heading | Title element via as (h3 default). Trailing action is a layout slot — pass a real <button> / Button with an accessible name. |
| Subtitle / desc | <p> elements. In typical composition they are announced after the heading and its action. |
Card.Badge | Presentational <span> with a single informative style. Meaning must be in the words, not a custom color. |
Card.MetaItem | Text plus optional icon wrapped with aria-hidden="true" so icons stay decorative. |
Card.Footer | Layout-only <div> (data-layout). Children should be labeled controls (Button, links with clear names). |
Focus & visuals
| Concern | EDS behavior |
|---|---|
| Focus | Root is not focusable. Nested EDS buttons draw their own :focus-visible rings. |
| Overflow | .eds-card uses overflow: clip for media/radius. Prefer controls with room inside the padding so focus rings are not clipped at the edge. |
| Contrast | Text uses --eds-color-text-* on --eds-card-bg / surface tokens. Spot-check partner themes and custom backgrounds. |
| RTL | Title sits at inline-start; heading action and layout="end" footer pack to inline-end. Farsi demos: dir="rtl" lang="fa" on a wrapping panel. |
| Motion | Card has no motion of its own; nested menus / loaders must respect prefers-reduced-motion. |
Build with it
| Do | Don’t | ||
|---|---|---|---|
Pick Card.Heading as so the title fits the page outline (h2 / h3 / …) | Style a div as a title and skip a real heading | ||
Pass meaningful alt on informative Card.Media; leave default "" when decorative | Repeat the full heading in alt, or omit alt on meaningful photography | ||
Use real Buttons (with aria-label when icon-only) in action and Card.Footer | Put click handlers on non-interactive wrappers inside the card | ||
| Keep one clear primary action in the footer (or a single navigational control) | Wrap the entire card in a link when nested buttons / overflow menus also exist | ||
| Write badge and meta copy that stands alone without color | Restyle Card.Badge so status is only a color, with no text meaning |
// Heading level + labeled overflow
<Card.Heading
as="h2"
action={
<Button
size="sm"
variant="ghost"
aria-label="More options"
iconStart={<Icon name="ellipsis-outline" />}
/>
}
>
Equinix Metal server
</Card.Heading>
// Decorative vs informative media
<Card.Media src="/hero.png" alt="" />
<Card.Media src="/rack.png" alt="Four servers in a colo rack" />Quick test
- Outline — In the accessibility tree / headings list, confirm each card title appears at the expected level (
as). - Keyboard — Tab through heading action and footer buttons; confirm a visible focus ring and activation with Enter/Space. Confirm the card surface itself is not a tab stop.
- Screen reader — Verify the heading, description, and button names are announced; decorative media is skipped; informative
altis read once. - Nested interactives — If you tried a whole-card link plus footer buttons, remove the outer link and re-test focus order.
- RTL — Open the RTL example; confirm title and body start on the right, and the heading
actionpluslayout="end"footer sit on the left. - Contrast — Check title/body text and badge borders on the real card background (including dark mode).