Skip to content

Components

Stacked Sheets — Drill-Down Navigation That Never Loses the Page

The Stack Is an Array, Escape Pops One, and Three Layers Is the Ceiling
Written by Aiden Wood Founder and Lead Design Engineer
🥞 🗂️ ↩️

Click an order → order sheet. Click the customer inside it → customer sheet slides over the order sheet, which recedes slightly behind it. Close the customer, the order is exactly where you left it. That's stacked sheets — the drill-down pattern Linear and Stripe normalised, and the reason their apps feel like you never lose your place.

Velocity X's standard-stacked-sheet-layers ships the mechanics; the design discipline is knowing where to stop.

The Money Pattern

The entire model is a stack in state — push to open, pop to close, render with depth-derived styling:

const [stack, setStack] = useState<SheetDef[]>([]);
const push = (sheet: SheetDef) => setStack(s => [...s, sheet]);
const pop = () => setStack(s => s.slice(0, -1));

{stack.map((sheet, i) => {
  const fromTop = stack.length - 1 - i;        // 0 = active sheet
  return (
    <aside
      key={sheet.id}
      aria-hidden={fromTop !== 0}
      style={`transform: translateX(-${fromTop * 24}px) scale(${1 - fromTop * 0.03});
              filter: brightness(${1 - fromTop * 0.06})`}
      class="fixed inset-y-0 right-0 w-[520px] rounded-l-2xl bg-white shadow-2xl
             transition-transform"
    >
      <sheet.Component {...sheet.props} />
    </aside>
  );
})}

Each layer below the active one nudges left, scales down a hair and dims — enough to read as "still there", cheap enough to be pure transform. Escape pops one layer, the scrim click pops one layer; only the explicit close-all affordance clears the stack. Focus moves to the new sheet on push and returns to the triggering element on pop — the detail that keeps keyboard users oriented.

The Catch

Three layers is the ceiling. Past that, the receding stack eats horizontal space, the user's mental model of "what's behind what" collapses, and the real fix is a navigation question: layer four usually means the drill-down should have been a page. The component warns in dev past depth 3 on purpose.

And decide the URL story up front: sheets that represent entities (an order, a customer) deserve a query param (?sheet=order_123) so refresh and share don't dump the user back to zero. Ephemeral sheets (filters, forms) shouldn't touch the URL. Mixing the two conventions in one app is how back-button behaviour becomes a bug report generator.

The Verdict

A stack array, depth-derived transforms, pop-one semantics, focus restoration, and a hard ceiling of three. Drill-down that keeps the page under the user's feet. It's in Velocity X's Standard Overlays & Menus — the application-surface tier, source you own.

Let us make some quick suggestions?

Please provide your full name.
Please provide your phone number.
Please provide a valid phone number.
Please provide your email address.
Please provide a valid email address.
Please provide your brand name or website.
Please provide your brand name or website.