COMPONENTS / MOLECULES / al-card← ALL COMPONENTS

Card

<al-card><ALCard> REACTbetaOPEN IN FIGMA ↗

Reference generated from the custom elements manifest — 3 properties, 7 slots, 0 events.

PLAYGROUND1 CONTROL
PREVIEW / al-card / ALTITUDE
Loading preview
Flat, minimal, type-first. Duplicate Favorite Remove MK M. Kim · 4h ago Active Same components, reimagined. Hairline borders on warm paper neutrals, one refined blue, shadows reserved for overlays. Public Sans for UI, IBM Plex Mono for metadata. Design Engineering Research Dismiss Continue
FLAGS
CODE — HTML / REACT

Guidance

AUTHORED · CITED TO SOURCE

A bounded surface that groups one subject — its media, its heading, its body and its actions — so a page can present many of them side by side and the user reads each as one thing. It is a container with named regions, not a layout: a card decides what goes where inside itself and nothing about how cards sit next to each other.

WHEN TO USE

  • You are showing a repeated set of objects — projects, jobs, articles, people — where each entry has its own actions.
  • A block of content needs to be visually separated from the page around it. variant="bare" keeps the regions and drops the background, shadow and radius.
  • Cards sit in a grid or a stretched row and their footers should line up. Set fill and every card in the row shares one height.

WHEN NOT TO USE

  • You only need to arrange boxes with spacing between them. Cards are a content container; the arrangement around them belongs to the layout primitive.USE LAYOUT →
  • The content is a single number with a label and a trend. That has its own component, with the typography and the delta treatment already decided.USE STAT →
  • You are showing rows of comparable fields that the user will scan down a column. A card per row destroys the comparison a table makes easy.USE TABLE →
  • There is nothing to separate — one card holding the whole page adds a border and no meaning.USE LAYOUT →

DO

  • Use fill rather than an inline height: 100% from the page. :host is display: contents, so a height written on <al-card> from outside is dropped entirely — this property exists because one app hit exactly that and worked around it at 25 call sites.
  • Put the primary action in actions-end, which is the canonical bottom-right position, and a secondary one in actions-start.
  • Use the image slot for media above the heading, including an avatar — that is the common case across the example apps.
  • Reach for layout="inline" when the media and the text should sit side by side rather than stacked.

DON’T

  • Don't slot content into action-right. The slot is documented on the component but the template renders no <slot name="action-right">, so anything assigned to it does not appear. Put an overflow control in actions-end until that is fixed.
  • Don't expect image to bleed to the card edge. The card carries a single outer padding and the image region neither resets nor negates it. A card that needs edge-to-edge media wants a component that renders it, not a flag here.
  • Don't make the whole card a link when it also contains buttons. Nested interactive regions leave the user with no way to tell which target they are about to hit.
  • Don't hand-roll a grid of cards with flex or grid in your own stylesheet. That is what the layout primitive's grid and bento variants are for.

ACCESSIBILITY IN PRACTICE

  • The card renders a plain <div> with no landmark or list semantics. If a set of cards is a list, the surrounding markup has to say so — the card will not.
  • Put a real heading in the header slot. The card provides the visual grouping; the heading is what gives a screen-reader user a way to navigate between cards.
  • Each action inside a card needs a label that makes sense out of context. Ten cards each containing "View" produce ten identical entries in a list of links.

CONTENT GUIDELINES

  • Lead with what distinguishes this card from the one beside it. The shared parts — the category, the label, the icon — are the least useful words in the first line.
  • Keep body text to what survives being scanned. A card is read in a grid, at a glance, alongside others.
  • Keep action labels consistent across every card in a set, so the row reads as one pattern rather than as variations.

WHERE THIS CAME FROM

  • libs/al-web-components/components/card/card.tsThe recorded correction about the `image` slot — the docs previously claimed edge-to-edge media and the code never did that.
  • libs/al-web-components/components/card/card.tsWhy `fill` has to be a property: `display: contents` means a height set from outside never applies.
  • libs/al-web-components/components/card/card.tsThe slot is declared in the component's documentation; the render function below it emits no matching slot element.
  • AGENTS.mdThe rule that keeps arrangement out of content components like this one.

Each line above names a file and a literal string that must still appear in it.pnpm gate:guidance re-reads them from this built page, so guidance that has stopped being true fails a check rather than misleading you.

CODE AHEADAltitude Design SystemFIGMA SET · Card3 PROPERTY DIFFSFROM TRACKED PROJECTION

The component changed since the last confirmed sync — the Figma set is behind.

DECIDED BY
NEVER SYNCED
FIGMA SIDE
OBSERVED
LAST CONFIRMED SYNC
NEVER
PUBLIC SURFACE
3 ATTR · 7 SLOT · 0 EVENT · 0 PART

The two sides have never been confirmed equal, so there is no baseline to compare against.

PROPERTYDISAGREEMENTCODE / CANVAS
fill[prop] missing-in-canvasfill / —
layout[prop] missing-in-canvaslayout / —
theme/border/width/@[token-binding] missing-in-canvas--al-theme-border-width / —
CHECKEVIDENCEDETAILRESULT
Default stateAXEcard--BarePASS
Advanced statesAXE5 further storiesPASS
Screen readerMANUALNo screen-reader pass has been recorded for this component.NOT RECORDED
Keyboard navigationINTERACTION TESTSNo interaction tests and no manual keyboard pass.NOT RECORDED

MEASURED 2026-09-08 · 6 STORIES · AXE WCAG2A + WCAG2AA + WCAG21A + WCAG21AA + WCAG22AA

COLOR CONTRAST0 RULES FAILING

The CI gate disables color-contrast globally (libs/al-web-components/story-fixture/src/main.ts), so its result never reaches a test run. It is enabled for this measurement, and reported here whichever way it comes out.

NO CONTRAST VIOLATIONS ACROSS THIS COMPONENT’S 6 STORIES.

import '@southleft/al-web-components/components/card';
import { ALCard } from '@southleft/al-react';
PROPTYPEDEFAULT
layout'inline'Layout - **default** Displays the slotted items stacked in a column - **row** Displays the slotted items inline in a row
variant'bare'Variant - **default** Renders a card with a background color, box shadow, or border radius - **bare** Renders a card without a background color, box shadow, or border radius
fillbooleanFill the available block size instead of hugging the content. For a card in a grid or a stretched flex row, where a row of cards should share one height and their footers should line up. Reflected, so a page can also select `al-card[fill]`. It has to be a property rather than something the page sets from outside: `:host` is `display: contents`, so `<al-card>` generates no box and a `height: 100%` written on the element is dropped entirely. `apps/southleft` hit exactly this and worked around it with `style="height:100%; box-sizing:border-box"` at 25 call sites across 13 files — that inline style is what this replaces.
SLOTDESCRIPTION
(default)The main content of the card (renders below the header).
actions-startTrailing-action row, leading edge (bottom-left). Use for a "View" / "Open" primary action.
actions-endTrailing-action row, trailing edge (bottom-right). Use for the canonical bottom-right primary action.
action-rightTop-right single control (kebab / overflow menu).
imageMedia rendered above the header, INSIDE the card's padding. Takes the full content width; an `<al-avatar>` sits here too, which is the common case across the example apps. NOT flush to the card edge — this line previously claimed it was, and it never has been: `.al-c-card` carries a single outer `padding` and `.al-c-card__image` neither resets nor negates it (card.scss). The claim was wrong rather than the code: the slot is used for avatars in `apps/angular`, `apps/astro` and `apps/svelte`, and bleeding it to the edge would wreck all of them. A card that needs edge-to-edge media wants a card that owns its own padding, not a flag here — see the `article` / `work` variants on Southleft's `al-card` in `libs/sl-web-components`, which move the padding onto the content column.
headerCard heading row. Rendered above a hairline rule. Compose the row itself with `<al-layout>` when it carries a title and a control.
footerCard footer row, below a hairline rule and on a tinted ground. Compose it with `<al-layout>` rather than relying on slot order.

THIS COMPONENT DECLARES NO EVENTS IN THE MANIFEST.

SOURCE — components/card/card.ts · Molecules/Card