Cards
DepthStack
Cards wait behind the front card and fan out on hover or keyboard focus. CSS only.
Download
- React
- Tailwind CSS v4
components/ui/depth-stack.tsx
import type { ReactNode } from "react";
type DepthStackProps = {
children: ReactNode;
className?: string;
/** Look of the cards behind. */
layerClassName?: string;
/** How many cards sit behind. */
layers?: number;
/** How far the cards fan out on hover, in pixels. */
spread?: number;
};
/* DepthStack: cards wait behind the front card and fan out on hover or keyboard focus. */
export function DepthStack({
children,
className = "rounded-2xl border border-white/10 bg-[#1b1830] p-6 text-white",
layerClassName = "rounded-2xl border border-white/10 bg-[#25213d]",
layers = 2,
spread = 14,
}: DepthStackProps) {
return (
<div
className="relative isolate hover:[--open:1] focus-within:[--open:1]"
>
{Array.from({ length: layers }, (_, i) => {
const n = i + 1;
const side = n % 2 ? 1 : -1;
return (
<div
key={n}
aria-hidden
className={`absolute inset-0 transition-transform duration-500 ease-[cubic-bezier(.2,.8,.2,1)] motion-reduce:transition-none ${layerClassName}`}
style={{
zIndex: -n,
opacity: 1 - n * 0.25,
transform: `translateY(calc(${n * 10}px + var(--open, 0) * ${n * spread}px)) rotate(calc(var(--open, 0) * ${side * n * 2}deg)) scale(${1 - n * 0.05})`,
}}
/>
);
})}
<div
className={`relative transition-transform duration-500 ease-[cubic-bezier(.2,.8,.2,1)] motion-reduce:transition-none ${className}`}
style={{ transform: "translateY(calc(var(--open, 0) * -6px))" }}
>
{children}
</div>
</div>
);
}
1. Paste the Code tab into
components/ui/depth-stack.tsx. The styles are Tailwind CSS v4 classes.2. Use it. This is the preview above:
app/depth-stack-demo.tsx
import { DepthStack } from "@/components/ui/depth-stack"; export default function DepthStackExample() { return ( <div className="grid h-full place-items-center bg-[#0b0a14] p-6"> <div className="w-full max-w-[300px]"> <DepthStack layers={3}> <p className="font-mono text-[11px] uppercase tracking-[0.2em] text-[#a78bfa]">Inbox</p> <p className="mt-3 text-2xl font-semibold">12 new messages</p> <p className="mt-2 text-sm text-white/60">Hover to fan out the stack.</p> </DepthStack> </div> </div> ); }
Props
| Name | Type | Default | What it does |
|---|---|---|---|
| children | ReactNode | — | Front card content. |
| layers | number | 2 | How many cards sit behind. |
| spread | number | 14 | How far they fan out, in pixels. |
| className | string | dark violet card | Look of the front card. |
| layerClassName | string | lighter violet card | Look of the cards behind. |