Search

Search the site

All components

Deck Stack

Card width preset. The outer container stays full width; cards are centered within it.

Default
Default deck stack

Card 3

Third item

Card 2

Second item

Card 1

First item

1"use client";
2
3import { DeckStack } from "@/registry/ui/deck-stack";
4
5export function DeckStackDefaultExample() {
6 return (
7 <DeckStack
8 items={[
9 { title: "Card 1", desc: "First item" },
10 { title: "Card 2", desc: "Second item" },
11 { title: "Card 3", desc: "Third item" },
12 ]}
13 renderCard={(item) => (
14 <div className="p-6 rounded-xl border bg-background">
15 <h3 className="text-lg font-semibold">{item.title}</h3>
16 <p className="text-sm opacity-70">{item.desc}</p>
17 </div>
18 )}
19 />
20 );
21}
Products
Products deck stack

Zero Config

Works out of the box

Type Safe

End-to-end TypeScript support

Edge Ready

Optimised for global distribution

Realtime Sync

Instant updates across all clients

1"use client";
2
3import { DeckStack } from "@/registry/ui/deck-stack";
4
5export function DeckStackProductsExample() {
6 return (
7 <DeckStack
8 size="lg"
9 autoplay
10 interval={4500}
11 items={[
12 {
13 title: "Realtime Sync",
14 desc: "Instant updates across all clients",
15 },
16 {
17 title: "Edge Ready",
18 desc: "Optimised for global distribution",
19 },
20 {
21 title: "Type Safe",
22 desc: "End-to-end TypeScript support",
23 },
24 {
25 title: "Zero Config",
26 desc: "Works out of the box",
27 },
28 ]}
29 renderCard={(item) => (
30 <div className="p-8 rounded-2xl bg-linear-to-br from-zinc-900 to-zinc-800 text-white shadow-xl">
31 <h2 className="text-xl font-semibold mb-2">{item.title}</h2>
32 <p className="text-sm opacity-80">{item.desc}</p>
33 </div>
34 )}
35 />
36 );
37}
Testimonials
Testimonials deck stack

We replaced our whole carousel system with this.

- Sam

The motion is ridiculously smooth. Feels like Apple UI.

- Jordan

This is the first component that actually feels physical.

- Alex
1"use client";
2
3import { DeckStack } from "@/registry/ui/deck-stack";
4
5export function DeckStackTestimonialsExample() {
6 return (
7 <DeckStack
8 size="sm"
9 autoplay
10 interval={6000}
11 items={[
12 {
13 name: "Alex",
14 quote: "This is the first component that actually feels physical.",
15 },
16 {
17 name: "Jordan",
18 quote: "The motion is ridiculously smooth. Feels like Apple UI.",
19 },
20 {
21 name: "Sam",
22 quote: "We replaced our whole carousel system with this.",
23 },
24 ]}
25 renderCard={(item) => (
26 <div className="p-6 rounded-xl border bg-white text-primary-foreground">
27 <p className="text-base leading-relaxed">{item.quote}</p>
28 <div className="mt-4 text-sm font-medium opacity-70">
29 - {item.name}
30 </div>
31 </div>
32 )}
33 />
34 );
35}
Interactive
Interactive deck stack

Or click dots (if you add them)

Or use arrows

Drag me

1"use client";
2
3import { DeckStack } from "@/registry/ui/deck-stack";
4
5export function DeckStackInteractiveExample() {
6 return (
7 <DeckStack
8 autoplay={false}
9 items={[
10 { label: "Drag me" },
11 { label: "Or use arrows" },
12 { label: "Or click dots (if you add them)" },
13 ]}
14 renderCard={(item) => (
15 <div className="p-8 rounded-xl border bg-background">
16 <p className="text-lg">{item.label}</p>
17 </div>
18 )}
19 />
20 );
21}

Installation & source

Install via the shadcn CLI or copy the registry files manually.

bash
npx shadcn@latest add @tt-ui/deck-stack

Props

NameTypeDefaultDescription
itemsT[]RequiredThe items to display in the deck stack
renderCard(item: T, index: number) => ReactNodeRequiredRenders one card surface for an item
size"sm" | "md" | "lg" | "xl" | "full""md"Card width preset. The outer container stays full width; cards are centered within it.
autoplay / intervalboolean / numbertrue / 5000Auto-advance and milliseconds between ticks
visibleCardsnumber4Maximum cards rendered in the visible stack
draggablebooleantrueAllow dragging the front card to advance or go back