Components / Data display
CardStack
Review a deck one card at a time, with a throw and an undo.
Install
npx shadcn@latest add https://irisui.dev/r/card-stack.jsonimport { CardStack } from "@/components/iris/card-stack/card-stack";Preview
CardStack
A deck of cards reviewed one at a time: throw the top card left or right, or use the buttons and arrow keys, with undo.
When to use
- Quick, one-by-one triage where each item deserves a moment: shortlisting firms for a raise, rooms to view, or design options.
- When the decision is binary (pass / keep) and order of review does not matter.
- Use a list or SortableDataTable when people need to compare items side by side, and Carousel to browse without deciding.
Usage
import { CardStack } from "@/components/iris/card-stack/card-stack";
h(CardStack, {
items: firms,
getKey: (firm) => firm.id,
getLabel: (firm) => firm.name,
renderCard: (firm) => h(FirmFace, { firm }),
label: "Firms for the seed raise",
labels: { left: "Pass", right: "Shortlist" },
outcomes: { left: "passed", right: "shortlisted" },
onDecide: (firm, side) => save(firm.id, side),
renderEmpty: (reset) => h(Button, { onClick: reset }, "Start over"),
});
Props
| Prop | Type | Default | Description |
|---|---|---|---|
items |
T[] |
— (required) | Cards in order; the first is on top. |
getKey |
(item) => string |
— (required) | Stable key. |
getLabel |
(item) => string |
— (required) | Short name used in the card's label and announcements. |
renderCard |
(item) => ReactNode |
— (required) | Card content. The stack draws the surface (border, radius, background); you fill it. |
onDecide / onUndo / onReset |
callbacks | — | (item, "left" | "right") for decide and undo; onReset() when all cards come back. |
labels |
{ left: string; right: string } |
{ left: "Pass", right: "Keep" } |
Button labels and the stamps shown while dragging. |
outcomes |
{ left: string; right: string } |
— | Past tense for announcements ("skipped", "shortlisted"). |
label |
string |
"Cards" |
Accessible name for the stack. |
renderEmpty |
(reset) => ReactNode |
— | Shown once every card is decided; receives a function that brings all cards back. Defaults to "All cards reviewed" with a Start over button. |
className |
string |
— | Extra class on the root. |
Notes
- Keyboard: Left/Right decide, Backspace or Cmd/Ctrl+Z undoes. Instructions are provided as a visually hidden hint and each decision is announced in a polite live region.
- Card height is fixed by the
--card-heightcustom property (19rem); keep content within it. - Under reduced motion cards fade instead of flying, and undone cards fade back in at home.