WebberUI

Stacked Peek Carousel

A card stack carousel where the layers behind peek out, and the next card moves up to take the front on each swipe.

The current card sits centered, with the 2–3 cards behind it shrunk and offset upward so their edges peek out. On a drag or a button press the front card flies out with a rotation while the card behind springs up to take its place, with wraparound looping and dot indicators — well suited to browsing curated content such as trip cards or product cards.

Loading preview…
npx shadcn@latest add https://webberui.com/r/stacked-peek-carousel.json

Playground

Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.

2
16
0.06
<StackedPeekCarousel />

Installation

npx shadcn@latest add https://webberui.com/r/stacked-peek-carousel.json

Or, once registries are configured in components.json, install it as @webberui/stacked-peek-carousel.

Usage

import { StackedPeekCarousel } from "@/components/ui/stacked-peek-carousel";

<StackedPeekCarousel
  items={[
    <TripCard key="kyoto" title="Kyoto · Arashiyama" />,
    <TripCard key="swiss" title="Switzerland · Jungfrau" />,
    <TripCard key="palau" title="Palau · Rock Islands" />,
  ]}
  peek={2}
  onIndexChange={(index) => console.log("now on card", index + 1)}
/>

Each item fills the stage area (h-72 w-64 by default, overridable with stageClassName), so give the card itself h-full w-full and a rounded background.

Props

PropTypeDefaultDescription
itemsReact.ReactNode[]The list of carousel card content; each node fills the stage area
peeknumber2Number of stacked layers peeking out behind
offsetnumber16Distance each stacked layer is offset upward (px)
scaleStepnumber0.06Scale reduction per stacked layer (0–1)
loopbooleantrueWhether to wrap around at the start and the end
showDotsbooleantrueWhether to show the dot indicators
showArrowsbooleantrueWhether to show the left and right switch buttons
stageClassNamestringSizing styles of the stage (the card stack area), h-72 w-64 by default
onIndexChange(index: number) => voidCallback fired when the current index changes
classNamestringForwarded to the outermost container

Accessibility

  • The stage is marked role="region" with aria-roledescription="carousel", and the total number of cards is stated in the label
  • The current position is announced live through an aria-live="polite" block as "card X of N"
  • The peeking cards behind are hidden from assistive technology with aria-hidden and have interaction disabled with pointer-events-none
  • The left and right buttons and the dots are all native buttons that can be focused and operated by keyboard, each carrying an aria-label for "previous / next / go to card N", with the current dot marked aria-current
  • When the user has "reduce motion" enabled at the system level, the drag gesture and the spring animation are disabled and switching completes instantly

On this page