Card stack
Review a deck one card at a time, with a throw and an undo.
pnpm dlx shadcn@latest add @uiarc/card-stackLive · keyboard ready
Spring offsite
0 shortlisted · 6 to review
LIS14–17 Oct
Lisbon
Portugal
Tiled hills, long lunches, and a riverside workshop space for 18.
- 3h 35m direct from Berlin
- 22° and mostly sunny
- From €780 per person
Drag the top card, or use the left and right arrow keys to skip or shortlist it. Backspace undoes the last decision.
- One-by-one triage such as shortlisting, review queues, or onboarding picks.
- Decks where swiping left or right should be undoable.
- Use a list or sortable-data-table when people compare items side by side.
- Use carousel to browse items without deciding.
- Use swipe-actions for quick actions on rows in a list.
Installation
Add Card stack with the shadcn CLI, or copy the source by hand.
pnpm dlx shadcn@latest add @uiarc/card-stackAdds the component and its local dependencies, and installs motion, lucide-react. First time? Add the @uiarc registry to components.json, or use the full URL:
example.tsx
import { CardStack } from "@/components/arc/card-stack/card-stack"; const cities = [{ id: "lis", name: "Lisbon" }, { id: "osl", name: "Oslo" }, { id: "kyo", name: "Kyoto" }]; export function Shortlist() { return ( <CardStack items={cities} getKey={city => city.id} getLabel={city => city.name} renderCard={city => <h3>{city.name}</h3>} labels={{ left: "Skip", right: "Shortlist" }} onDecide={(city, decision) => save(city.id, decision)} /> );}CardStack
A deck reviewed one card at a time by swiping left or right, with buttons, undo, and reset.
PropTypeDefaultDescription
itemsRequiredT[]–Cards in order.getKeyRequired(item: T) => string–Stable key per item.getLabelRequired(item: T) => string–Short name for labels and announcements, such as "Lisbon".renderCardRequired(item: T) => ReactNode–Card content.onDecide(item: T, decision: "left" | "right") => void–Called when a card is swiped or decided by button or key.onUndo(item: T, decision: "left" | "right") => void–Called when the last decision is undone.onReset() => void–Called when all cards come back.labels{ left: string; right: string }{ left: "Pass", right: "Keep" }Action names on the buttons and drag stamps.outcomes{ left: string; right: string }–Past tense of each action for announcements, such as "skipped".labelstring"Cards"Accessible name for the stack.renderEmpty(reset: () => void) => ReactNode–Shown once every card is decided. Defaults to a Start over button.classNamestring–Class for the root.- ArrowLeftorArrowRight
- Decides the top card left or right when the stack is focused.
- BackspaceorCmd+ZorCtrl+Z
- Undoes the last decision.
- The stage is a focusable role="group" with aria-roledescription="card stack" and a hidden hint describing drag and keys.
- Each card is labelled like "Lisbon, 1 of 3".
- Decisions, undo, and reset are announced in a polite status region.
- Buttons mirror every gesture, so swiping is never required.
- The top card follows the drag with tilt and stamps; a flick or far drag throws it off with its velocity.
- Cards beneath rise into place, and undo flies a card back from where it left.
- Reduced motion fades cards out and in at home without travel.
- The stage is min(100%, 20rem) wide; below 26rem the cards get shorter, and below 22.5rem Undo becomes icon-only.
- Cards use touch-action pan-y, so vertical swipes still scroll the page.
- Only the top four cards render in the stage, however long the deck.
- Drag and throw run on motion values without per-frame React updates.
Notes for AI
Give your coding assistant the Markdown reference instead of screenshots.
- Use for one-by-one triage: shortlisting, review queues, onboarding picks. Use a list or sortable-data-table when people compare items side by side.
- Persist decisions from onDecide and reverse them in onUndo.
The full library index for assistants is at /llms.txt.