Carousel

Browse a row of slides by dragging, flicking, or arrowing through them.

carouselslidergallery
Preview
Carousel preview

Harbour suites

Old town lofts

Wine cellar stay

Hilltop villa

Lakeside cabin

When to use

  • A short set of peer items where neighbouring slides hint at more.
  • Galleries browsed by drag, flick, trackpad swipe, or keys.
  • Rotating highlights with a visible pause control, via interval.

When not to use

  • Use cover-flow for a showpiece gallery and photo-grid to show everything at once.
  • Use card-stack for deciding on items one at a time.

shadcn CLI

Also installs (1)

  • manicat-foundation
Manual install(+)
registry.jsonjson
{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "carousel",
  "type": "registry:ui",
  "title": "Carousel",
  "description": "Browse a row of slides by dragging, flicking, or arrowing through them.",
  "categories": [
    "data"
  ],
  "dependencies": [
    "lucide-react",
    "motion"
  ],
  "registryDependencies": [
    "https://manicat.viraza.net/r/manicat-foundation.json"
  ],
  "files": [
    {
      "path": "registry/components/carousel/carousel.tsx",
      "type": "registry:component",
      "target": "@components/manicat/carousel/carousel.tsx"
    },
    {
      "path": "registry/components/carousel/carousel.module.css",
      "type": "registry:component",
      "target": "@components/manicat/carousel/carousel.module.css"
    }
  ],
  "docs": "Docs and live preview: https://uiarc.dev/components/carousel",
  "meta": {
    "tier": "free",
    "kind": "component",
    "docs": "https://manicat.viraza.net/components/carousel",
    "markdown": "https://uiarc.dev/components/carousel/markdown",
    "tags": [
      "carousel",
      "slider",
      "gallery"
    ]
  }
}

Usage

Install the component, then copy this into your app. Change the content and the props to fit your screen.

example.tsxtsx
"use client";

import { Carousel } from "@/components/manicat/carousel/carousel";

const slides = [
  { title: "Harbour suites", tone: "from-sky-400 to-blue-600" },
  { title: "Old town lofts", tone: "from-rose-400 to-red-600" },
  { title: "Wine cellar stay", tone: "from-amber-400 to-orange-600" },
  { title: "Hilltop villa", tone: "from-emerald-400 to-green-600" },
  { title: "Lakeside cabin", tone: "from-indigo-400 to-violet-600" },
];

export function CarouselExample() {
  return (
    <Carousel label="From the Harbour suites" slideSize="72cqw">
      {slides.map((slide) => (
        <div
          key={slide.title}
          className={`flex aspect-[4/3] items-center justify-center rounded-[var(--radius-panel)] bg-gradient-to-br ${slide.tone}`}
        >
          <p className="font-medium text-white">{slide.title}</p>
        </div>
      ))}
    </Carousel>
  );
}

Examples

Real screens rather than isolated props. Switch to Code to copy a whole example into your project.

Property gallery Drag, swipe or use the arrows; slides snap to a fixed width so the next one peeks in.

Property gallery Drag, swipe or use the arrows; slides snap to a fixed width so the next one peeks in. preview

Harbour suites

Old town lofts

Wine cellar stay

Hilltop villa

Keyboard interactions

KeysAction
ArrowLeft / ArrowRightMoves to the previous or next slide.
Home / EndJumps to the first or last slide.
TabMoves between the slide area, play control, active indicator, and arrows.

Accessibility

  • The root is a section with aria-roledescription="carousel"; slides are labelled tabpanels and the indicators a role="tablist".
  • Inactive slides are inert, so their links are not focusable.
  • Slide changes are announced in a polite live region.
  • Rotation pauses on hover, keyboard focus, and drag, and has a visible pause control.

Motion

  • Slides follow the finger and settle with momentum; neighbors shrink and dim with distance.
  • The indicator stretches into a pill that tracks the slides, and drains to show rotation time.
  • Reduced motion jumps between slides and disables rotation.

Responsive behavior

  • Slides default to min(80cqw, 340px), so they size to the carousel's container rather than the viewport.
  • Controls tighten when the container is under 340px.

Performance

  • All slides stay mounted; inactive ones are inert, so keep the set short.
  • Rotation pauses offscreen via IntersectionObserver and in hidden tabs via visibilitychange.

Notes for AI

  • Use for a short set of peer items where neighbors should hint at more. Use cover-flow for a showpiece gallery and photo-grid to show everything at once.
  • Give each slide a stable key if the list can change, and write a specific label.
  • Keep autoplay off unless rotation is essential.