Stacking Cards

Cards that pin and pile up as the page scrolls, each one behind shrinking and fading back a little.

Examples

Project cards with scenes

Selected work

Four projects from the Quillstone studio

Tidewell ferries

Timetables riders read at a glance

Every crossing of the day on one screen, with the next boat first and the last one marked before it is too late.

2026
Brightmoor library

A catalogue search that forgives typos

Readers find the book they half remember. Loans went up in the first month, and the desk gets fewer calls.

2025
Ashgrove clinic

Booking a visit in three taps

Patients pick a reason, a day and a doctor. The receptionist sees the morning fill up before the phones ring.

2025
Fernhill farm shop

Weekly boxes ordered by Thursday

Customers swap what they do not want and the farm knows how much to pick on Friday morning.

2024
More work on request

Principles

How we review a design

1 of 4

Read the brief again

Before anyone comments on a screen, someone reads the problem out loud. Half of the feedback answers a question nobody asked.

2 of 4

Fill it with real data

Long names, empty lists, a price with six digits. A design that only works with the sample data is not finished.

3 of 4

Remove one thing

Every review ends with one element taken out. If nobody misses it a week later, it stays out.

4 of 4

Show five people

Five people who were not in the room try it while we watch, without a word from us.

Installation

npx shadcn@latest add https://ui.ndekocode.dev/r/motion-stacking-cards.json

Component API

StackingCards

Each card gets a pinned frame as tall as the scrolling area. The deepest card ends at 90% of its size and the one on top stays at full size; the scale and the fade follow the scroll position directly, without re-rendering. With reduced motion, the cards are a plain list at full size.

PropTypeDefaultDescription
childrenReact.ReactNodeThe StackingCard elements.
containerRefRefObject<HTMLElement | null>The scrolling element, when it is not the page. It needs a non-static position.
frameClassNamestringh-svhClasses of each pinned frame. Its height should match the scrolling area.
peeknumber16How many pixels of each card stay visible above the next one.
classNamestringundefinedOptional CSS class for the stack.

StackingCard

PropTypeDefaultDescription
childrenReact.ReactNodeThe content of the card. Give every card the same height so the edges line up.
classNamestringundefinedClasses of the card surface: background, ring, radius and width.