affectUI › Components › Cards
Card
The card every screen is built from – header with title, quiet line and an action, content and a footer, the whole card a click target and a gray fill when selected.
Free and open source (MIT). Install: npx shadcn@latest add https://www.affectui.com/r/card.json · Import from @/components/ui/card
When to use
- A self-contained thing on a page: an agent, a project, an integration, a plan – with its name, a line about it and an action
- A settings group: its title and note on top, the fields inside, Save in the footer
- A grid or list of things to open – interactive, with a link as the title
- A small set of choices shown as cards – interactive and selected, with aria-pressed on the title's button
When not to use
- A floating panel on top of the page – use the Popover or the Dialog
- Rows of a long list – plain rows with hairlines between them read faster than a stack of cards
- Only a line between groups – use the Separator
- One of the purpose-built cards: Approval Card, Decision Card, Project Card – they come with their behavior
Usage
import { Card, CardContent, CardFooter, CardHeader } from "@/components/ui/card";
export function AgentCard() {
return (
<Card>
<CardHeader
title="Support triage"
description="Sorts new tickets and drafts the first reply"
action={<button aria-label="More">⋯</button>}
/>
<CardContent>142 tickets this week · 96% resolved</CardContent>
<CardFooter>
Running · started 2 min ago
<button style={{ marginInlineStart: "auto" }}>Open</button>
</CardFooter>
</Card>
);
}Props
| Name | Type | Default | Description |
|---|---|---|---|
Card · as | "div" | "section" | "article" | "li" | "div" | The element it renders as – li inside a <ul> of cards, section or article when it stands for a part of the page |
Card · interactive | boolean | The whole card is a click target: it lifts on hover and a link or button in the title stretches over the card. Other buttons and links inside stay clickable on their own | |
Card · selected | boolean | Shown as picked: a gray fill and a firmer edge, no colored ring. Say it to screen readers too – aria-pressed or aria-current on the title's button or link | |
CardHeader · title | ReactNode | The title, in an h3 by default. A link or button here makes an interactive card clickable | |
CardHeader · description | ReactNode | A quiet line or two under the title | |
CardHeader · icon | ReactNode | Something small at the start – an icon, a logo, an agent's mark or a tile with one | |
CardHeader · action | ReactNode | At the end of the title line, centred on it: an icon button, a menu, a badge | |
CardHeader · titleAs | "h2" | "h3" | "h4" | "p" | "h3" | The title's element – pick the level that fits your page, or p for cards in a list of choices |
CardHeader · children | ReactNode | Anything more under the title and description, e.g. a row of badges | |
CardContent | ComponentProps<"div"> | The card's body – any content | |
CardFooter | ComponentProps<"div"> | A row at the bottom in quiet 12.5px text, on the gray tray under the card. Status or meta on the start; give the first button marginInlineStart: auto to push the buttons to the end. Put it directly inside Card | |
...props | ComponentProps<"div"> | className, style, id, ref, onClick and the rest go to each part's element |
Keyboard
- Tab: An interactive card is reached through the link or button in its title – the ring goes around the whole card – then through the other buttons inside
- Enter: Opens the title's link or presses its button
- Space: Presses the title's button
Accessibility
- The title is a real heading (h3 by default), so screen-reader users can jump from card to card
- Interactive cards keep one click target – a link or button in the title – instead of a clickable <div>, so it's announced with its name and works from the keyboard
- Buttons inside an interactive card stay separate targets above the stretched title; don't nest a second link that does the same thing
- Selected is shown with a gray fill and edge, not color – say it with aria-pressed or aria-current as well
- In Windows high-contrast mode the card keeps a visible edge, and a selected card a highlighted one
Responsive
- Fills its container's width – set width on a grid or the card's style
- Long titles and unbreakable words wrap inside the card instead of pushing it wider; the footer wraps its buttons onto a new line when narrow
- No hover lift on touch screens, so it doesn't stick after a tap
- Logical properties – right-to-left text mirrors the header and the footer
- Dark mode built in: switches when an ancestor (usually <html>) has the class dark or data-theme="dark"
Requirements
- React 19
Related
- Separator – A thin line between groups – across or upright between tools, an optional word in its middle like "or" or "Earlier", decorative or a real separator for screen readers
- Badge – A small status label that carries the color – six soft tones, a leading dot or icon, a live dot that pulses while something runs and a round count up to 99+
- Avatar – A person's picture or initials on a soft color of their own – rounded squares for workspaces, an agent's pixel mark that twinkles while it works, a status dot and a group that overlaps and ends in +N
- Project Card – A two-line project summary that quietly unfolds on hover – a progress ring with one segment per subtask, a people filter and a status picker, all linked by hover
- Icon Button – A square button that is only an icon – ghost, outlined or solid, two sizes, a pressed state for toggles and its label as the tooltip