Skip to content
WANCRAFT

H.1213D & Experimental

Cube Carousel

Slides on the faces of a 3D cube that turns with a spring — drag, keys, buttons or auto-rotate.

NewReactMotionCSSTailwindadvanced

Overview

Cube Carousel puts slides on the four side faces of a CSS 3D cube (with top and bottom caps, so a tilted cube reads as solid). Turn it with the previous/next buttons, the arrow keys while the stage is focused, or by dragging: the release velocity carries into a configurable spring that snaps to the nearest face, never more than one face per flick. More than four items reuse the faces — whenever the cube settles, the faces beside the front one are refilled with the neighbouring items and the hidden back face is refilled silently. Auto-rotation pauses on hover, keyboard focus, offscreen and in hidden tabs, with a stop/start button. Only the front face is interactive; the rest are inert and hidden from assistive tech, and the front slide is announced as "Face 2 of 4: title". With reduced motion the cube becomes a flat panel that crossfades between slides.

01Installation

Method 01 · Registry

CLI verified

Uses the shadcn CLI in a project initialised with shadcn init. Installs the file to components/ui/cube-carousel.tsx and adds its dependencies.

npx shadcn@latest add https://wancraft.my/r/cube-carousel.json

Method 02 · Copy and paste

  1. 1. Install the dependencies below.
  2. 2. Copy the source from the Code tab into components/ui/cube-carousel.tsx.
  3. 3. Import it and adjust props.
npm install motion
Dependencies
motion
Peer
react ≥ 18, tailwindcss ≥ 4
Added
13 Oct 2026
Updated
—

02Usage

The default configuration. Change properties above to generate a tailored example in the Usage tab.

example.tsx
import { CubeCarousel, type CubeCarouselItem } from "@/components/ui/cube-carousel";

export function CubeCarouselExample() {
  const items: CubeCarouselItem[] = ["Research", "Sketch", "Build", "Ship"].map((title, i) => ({
    id: title.toLowerCase(),
    label: title,
    content: (
      <div className="flex h-full flex-col justify-between p-6">
        <span className="font-mono text-xs text-zinc-500">0{i + 1}</span>
        <p className="text-2xl font-semibold tracking-tight">{title}</p>
      </div>
    ),
  }));

  return (
    <CubeCarousel items={items} label="Process" />
  );
}

03Props

PropTypeDefaultDescription
items{ id: string; content: ReactNode; label: string }[]—Slides. More than four reuse the faces; label names the slide and is announced.
labelstring"Featured"Accessible name of the carousel.
widthnumber300Face width (and cube depth) in px.
heightnumber0.7 × widthFace height in px.
perspectivenumber1100CSS perspective in px.
tiltnumber-8Cube tilt in degrees (negative looks down onto the top).
spring{ stiffness: number; damping: number; mass: number }{ stiffness: 170, damping: 22, mass: 1 }Spring for turns and snaps.
autoRotatebooleantrueTurn one face per interval; pauses on hover, keyboard focus, offscreen and hidden tabs. Off with reduced motion.
intervalnumber3600Auto-rotate interval in ms (minimum 1500).
showControlsbooleantruePrevious, stop/start and next buttons plus the counter.
accentstring"#FF7448"Front-face edge, focus ring and control colour.
defaultIndex / onIndexChangenumber / (index) => void0Initial item; called when the front item changes.

04Features

  • 01Four CSS 3D side faces plus top and bottom caps, shaded by their angle to the viewer
  • 02Drag to turn with a velocity-carrying spring snap (max one face per flick); a drag never clicks the content
  • 03Any number of items: faces beside the front are refilled as the cube settles, the hidden back face silently
  • 04Buttons and Left/Right arrow keys; repeated presses accumulate
  • 05Auto-rotation that pauses on hover, keyboard focus, offscreen and hidden tabs, with a stop/start button
  • 06The scene scales down to fit narrow containers
motion · springmotion · continuousinput · draginput · pointerinput · clickinput · keyboardinput · focusinput · viewport

05Accessibility

  • A <section> with aria-roledescription="carousel"; each face is a group with aria-roledescription="slide" named "2 of 4: title".
  • Only the front face is interactive: the other faces are inert and aria-hidden, and the caps are decorative.
  • The focusable stage turns with Left/Right arrows; buttons are labelled and have visible focus outlines.
  • A polite live region announces "Face 2 of 4: title"; it is silenced while rotating automatically.
  • Auto-rotation can be stopped with a button and pauses on keyboard focus (WCAG 2.2.2).
  • prefers-reduced-motion replaces the cube with a flat panel that crossfades, and turns auto-rotation off.

06Limitations

  • With two or three items the neighbouring faces repeat items (they are inert and hidden from assistive tech).
  • Face content renders inside a 3D-transformed layer; heavy content can soften text on some GPUs.