Wallet stackPro

Fan a stack of cards and lift one out to see its activity.

Live · keyboard ready

Jordan’s cards

Arrow keys switch cards. Enter opens a card and Escape puts it back.

Fieldnote Everyday debit in front, 1 of 4

  • A few payment cards, passes, or memberships where people open one to see its balance and activity.
  • Fintech or wallet screens that want a physical card metaphor with realistic materials.
  • Use card-stack for generic swipeable content that is not a card wallet.
  • Use a plain list or data-grid for many accounts.
  • Use expandable-card when one card just needs to grow in place.

Installation

Pro source and install commands unlock with a Pro plan.

example.tsx
import { WalletStack } from "@/registry/components/wallet-stack/wallet-stack"; export function Cards() {  return (    <WalletStack      cards={[        { id: "debit", issuer: "Northbank", product: "Everyday debit", lastFour: "4821", holder: "Ada Lovelace", expires: "09/29", variant: "metal",          balance: 2480.5, balanceLabel: "Available",          transactions: [{ id: "t1", merchant: "Blue Bottle", detail: "Coffee · Today", amount: -6.5 }] },        { id: "travel", issuer: "Northbank", product: "Travel credit", lastFour: "0917", holder: "Ada Lovelace", expires: "03/28", variant: "color", tint: "oklch(42% .15 262)",          balance: 812.4, balanceLabel: "Spent this month", transactions: [] },      ]}      onSelectedChange={card => console.log(card?.id)}    />  );}

WalletStack

A stack of payment cards with real materials and depth: brushed metal, a guilloche black card, frosted glass, and deep color, each with an EMV chip, contactless mark, embossed number, and a light that follows the pointer or device tilt. Hover to fan the stack, drag or use the arrow keys to cycle cards, and choose a card to lift it into its balance and recent activity.

PropTypeDefaultDescription
cardsRequired{ id: string; issuer: string; product: string; lastFour: string; holder: string; variant?: "metal" | "black" | "glass" | "color"; tint?: string; expires?: string; network?: ReactNode; image?: string; balance: number; balanceLabel: string; transactions: { id: string; merchant: string; detail: string; amount: number; icon?: ReactNode; avatar?: string }[] }[]–Cards in stack order, the first in front. variant picks the material (metal by default); tint is any CSS color for the color variant; expires shows as Valid thru; network replaces the built-in fictional Halo mark, or null hides it; image is optional artwork under the finish. Amounts are negative for spending and positive for money in; avatar replaces the icon for transfers between people. The older finish field still works: paper maps to metal, graphite to black, clay and photo to color.
labelstring"Wallet"Heading above the stack, also its accessible name.
currencystring"USD"ISO currency code for balances and amounts.
localestring"en-US"Locale for number formatting.
onSelectedChange(card: WalletCard | null) => void–Called with the opened card, or null when it goes back into the stack.
classNamestring–Extra class on the root.
Arrow keys
Down or Right brings the next card to the front, Up or Left the previous one. While a card is open they switch the open card. Home and End jump to the first and last card.
EnterorSpace
Opens the front card into its balance and activity, or puts the open card back.
Escape
Puts the open card back into the stack and returns focus to it.
  • The stack is a labelled group with a described keyboard hint. Only the front card is in the tab order (roving tabindex); each card is a button named by issuer, product, last four digits, position, and balance, with aria-expanded while open.
  • The masked digits and decorative artwork are hidden from assistive technology; only the last four digits are read.
  • The activity region is inert until a card is open; the header switches from the card count to an All cards button that closes it.
  • Cycling and opening are announced in a polite live region, and focus returns to the card when it goes back into the stack.
  • Every card's transform is one pure function of a continuous stack position, the open amount, and the fan amount, so springs, drags, and interruptions all move the same shape. Z order never changes, so cards never pop over one another.
  • Hovering fans the stack upward on a no-overshoot spring; the hovered card rises out of the fan and its shadow deepens. The front card tilts up to 5 degrees and a specular highlight follows the pointer, or device tilt on phones that report it.
  • Dragging down pushes the front card into the pocket at the bottom and brings the next one forward one to one under the pointer; dragging up pulls it back. A flick lands where its momentum projects, one card at a time, with rubber banding past the first and last card.
  • Choosing a card lifts it to the top on one critically damped spring while the others tuck into the pocket; its balance counts up and three transactions stagger in. Pull the open card down to put it back, or flick it.
  • Only transform and opacity animate: shadows fade their opacity, the light moves a pre-painted layer. MotionConfig and a reduced motion branch remove travel, tilt, and the light; state changes apply instantly.
  • The wallet is min(100%, 18.5rem) wide. Cards keep the ID-1 ratio of 85.6 by 53.98 and every detail is sized in container units, so the card scales as one object; the stage height follows the card height.
  • The stage uses touch-action pan-x, so a vertical drag cycles cards while horizontal page gestures still work. An open card switches to touch-action none so it can be pulled down by touch.
  • Pointer tilt and the fan react to mouse only; on phones that report device orientation the light follows the tilt of the device instead.
  • Position, open amount, fan, and stage size are motion values, so gestures and springs never re-render React; the stage is measured once before paint and on resize.
  • Only transform and opacity animate. Shadows and the specular light are painted once and faded or moved; the stage clips vertically instead of masking so the glass card's backdrop blur stays cheap and correct.
  • Every card renders its artwork and transactions; keep the stack to a handful of cards.

Notes for AI

Give your coding assistant the Markdown reference instead of screenshots.

  • Choose it for a few payment cards, passes, or memberships where people open one at a time to see its activity. Use card-stack for generic swipeable content and a plain list for many accounts.
  • Pass fully shaped cards including balanceLabel and transactions, and a variant per card so the materials read as different cards. Selection is managed internally and reported through onSelectedChange.
  • The network mark is fictional. Never pass real card numbers; only lastFour is shown.

The full library index for assistants is at /llms.txt.