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.