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
default-example.tsx
1"use client";23import { DeckStack } from "@/registry/ui/deck-stack";45export function DeckStackDefaultExample() {6 return (7 <DeckStack8 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
products-example.tsx
1"use client";23import { DeckStack } from "@/registry/ui/deck-stack";45export function DeckStackProductsExample() {6 return (7 <DeckStack8 size="lg"9 autoplay10 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
testimonials-example.tsx
1"use client";23import { DeckStack } from "@/registry/ui/deck-stack";45export function DeckStackTestimonialsExample() {6 return (7 <DeckStack8 size="sm"9 autoplay10 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
interactive-example.tsx
1"use client";23import { DeckStack } from "@/registry/ui/deck-stack";45export function DeckStackInteractiveExample() {6 return (7 <DeckStack8 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
| Name | Type | Default | Description |
|---|---|---|---|
| items | T[] | Required | The items to display in the deck stack |
| renderCard | (item: T, index: number) => ReactNode | Required | Renders 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 / interval | boolean / number | true / 5000 | Auto-advance and milliseconds between ticks |
| visibleCards | number | 4 | Maximum cards rendered in the visible stack |
| draggable | boolean | true | Allow dragging the front card to advance or go back |