Card Swap
Cards swap positions and stacking order with layout animation, the front card arcing around to the back to form a 3D deck that breathes.
A stack of cards with 3D perspective: the front card falls along an arc and swings around to the back while the rest move forward together, producing a continuously looping stack swap.
Loading preview…
npx shadcn@latest add https://webberui.com/r/card-swap.jsonPlayground
Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.
2800
44
44
0
4
<CardSwap />
Installation
npx shadcn@latest add https://webberui.com/r/card-swap.jsonOr, once registries are configured in components.json, install it as @webberui/card-swap.
Usage
Each direct child is one card, and the component stacks and cycles them automatically.
import { CardSwap } from "@/components/ui/card-swap";
<CardSwap interval={2800}>
<div className="p-6">First</div>
<div className="p-6">Second</div>
<div className="p-6">Third</div>
</CardSwap>Set interval to 0 to turn off the automatic cycle and keep only click-to-swap (clickToSwap).
Props
| Prop | Type | Default | Description |
|---|---|---|---|
children | React.ReactNode | — | Each direct child is one card; 2–6 is recommended |
interval | number | 2800 | Interval of the automatic cycle (milliseconds); set 0 to turn it off |
offsetX | number | 44 | Horizontal offset per layer toward the back (px) |
offsetY | number | 44 | Vertical offset per layer toward the back (px) |
scaleStep | number | 0.07 | Scale reduction per layer toward the back |
depthStep | number | 60 | Distance each layer recedes along the Z axis (px) |
rotateStep | number | 0 | Additional rotation per layer toward the back (deg) |
maxVisible | number | 4 | Maximum number of layers visible at once; cards beyond it fade out |
direction | "up" | "down" | "up" | Direction the stack grows |
perspective | number | 1200 | 3D perspective distance (px); smaller values make the perspective stronger |
pauseOnHover | boolean | true | Pause the cycle when the mouse enters |
clickToSwap | boolean | true | Clicking a card advances to the next one |
cardClassName | string | — | Styles applied to each card's frame (including its size) |
Accessibility
- When the user has "reduce motion" enabled at the system level, the automatic cycle stops and the whole stack is presented statically
- No randomness is involved, and two-pass rendering behind a mounted flag avoids SSR hydration mismatches
- The animation uses only CSS 3D transforms, and timers are cleared when the component is left