Carousel
A horizontally or vertically scrolling set of slides with prev/next controls.
@garn/ui/carouselOn this page
Default
Five numbered slides with prev/next.
Installation
garn is copy-in — the garn CLI writes this component's source into your project, so you own and can edit it. It resolves any base files and installs the npm dependencies below for you.
npx garn-ui add carousel- Registry
carousel- Deps
embla-carousel-reactlucide-react- Registry deps
buttonutils
Import
import { Carousel, CarouselContent, CarouselItem, CarouselPrevious, CarouselNext } from "@garn/ui/carousel";Anatomy
The parts this component is built from — compose them to assemble it.
CarouselRequired[data-slot="carousel"]Root (role=region, aria-roledescription=carousel) — sets orientation/opts/plugins, exposes the Embla api via setApi, and handles arrow-key nav.
CarouselContentRequired[data-slot="carousel-content"]The Embla viewport + flex track that holds the items.
CarouselItemRequired[data-slot="carousel-item"]One slide (role=group, aria-roledescription=slide); full-basis by default.
CarouselPrevious[data-slot="carousel-previous"]Previous-slide Button; auto-disables at the start.
CarouselNext[data-slot="carousel-next"]Next-slide Button; auto-disables at the end.
Props
The component's public props and their types.
opts- Description
- Embla options (loop, align, dragFree, …) passed straight to the engine.
- Type
Partial<OptionsType>
orientation- Description
- Scroll axis; sets the Embla `axis` and the track's flex direction.
- Type
"horizontal" | "vertical"- Default
"horizontal"
plugins- Description
- Embla plugins (autoplay, wheel gestures, …).
- Type
CreatePluginType<LoosePluginType, {}>[]
setApi- Description
- Receives the Embla `api` once ready — for programmatic control or a dot indicator.
- Type
(api: CarouselApi) => void
Plus 280 inherited native HTML attributes.
Styling
Target these data-slots and states, and remap these tokens, to restyle without forking the component.
[data-slot="carousel"]States
| Selector | State | Description |
|---|---|---|
| cannot-scroll-prev | At the first slide — CarouselPrevious is disabled. |
| cannot-scroll-next | At the last slide — CarouselNext is disabled. |
When to use
Show a set of peer items (images, cards, testimonials) in a swipeable/steppable track when they don't all fit at once.
Reach for something else when
- Essential content users must not miss (don't hide it off-screen)
- a long ordered list (use a list + pagination)
- switching between distinct views (use tabs).
Overview
Carousel shows a set of peer items — images, cards, testimonials — in a swipeable/steppable track when they don't all fit at once. Carousel is the Embla-backed region (sets orientation/options, handles arrow keys), CarouselContent the track, CarouselItem each slide, with CarouselPrevious/CarouselNext auto-disabling at the ends. Use it for browsable peer media; for content users must not miss, lay it out directly — carousels hide everything but the current slide.
Guidelines
Use a carousel only for genuinely optional, peer content. Anything important shouldn't depend on a user swiping to find it — carousels have low engagement past the first slide. A short, equally-weighted set (a gallery, featured cards) is the sweet spot.
Make navigation obvious and keyboard-operable. Show prev/next controls and position indicators; the track responds to arrow keys and the buttons disable at the ends — don't hide the only way to advance behind a hover. Let users control the pace.
Avoid aggressive autoplay. If it auto-advances, make it slow, pausable, and stopped on focus/hover; honor reduced-motion. Each slide is announced as one of N — keep slides self-contained so they make sense out of sequence.
Best practices
- Give the Carousel an aria-label; keep prev/next reachable.
- If you autoplay, provide a pause/stop control (and respect reduced motion).
- Grab the Embla
apiviasetApiwhen you need programmatic control or a dot indicator.
- Don't bury important content in later slides.
- Don't autoplay without a way to pause.
- Don't use a carousel where the items should all be visible (use a grid).
Content guidelines
- Give every slide a concise caption or alt text — don't rely on position alone.
- Label the previous/next controls and any slide indicators for assistive tech.
Troubleshooting
useCarousel throws 'must be used within a <Carousel />'.
Cause. CarouselContent/Item/Previous/Next read context from the Carousel root.
Fix. Wrap all carousel parts in a single <Carousel>…</Carousel>.
Prev/Next don't appear or get clipped.
Cause. They're absolutely positioned just outside the track; a tight/overflow-hidden container hides them.
Fix. Leave horizontal room around the Carousel (or reposition the controls).
Accessibility
- Role
region
Keyboard
| ArrowLeft | Previous slide (when the carousel has focus). |
| ArrowRight | Next slide (when the carousel has focus). |
- Root is role=region aria-roledescription="carousel"; each item is role=group aria-roledescription="slide".
- Give the carousel an accessible name (aria-label) describing what it contains.
- Prev/Next have sr-only labels and disable at the ends so state is conveyed without color.