Carousel
<Carousel> wraps Embla with the design system’s controls. Use sparingly — the eye scans grids better than carousels for most data.
When to use
- Onboarding hero slides where horizontal motion adds context.
- Image-rich entity galleries (rare in admin; common in e-commerce).
- Constrained-width areas where vertical scroll is already in use.
Don’t use Carousel for: lists with exact-match retrieval (use a table or grid + filters), settings (auto-rotation hurts clarity), or “showcase” carousels users have to wait through. Auto-rotate is forbidden by default.
One slide visible
Slide 1
1
Slide 2
2
Slide 3
3
Slide 4
4
Slide 5
5
<Carousel> <CarouselContent> {items.map((it, i) => ( <CarouselItem key={i}>{/* slide */}</CarouselItem> ))} </CarouselContent> <CarouselPrevious /> <CarouselNext /></Carousel>Multiple slides visible
Set opts={{ align: 'start' }} and size each item with Tailwind basis (basis-1/3).
1
2
3
4
5
6
7
<Carousel opts={{ align: 'start' }}> <CarouselContent> {items.map((it, i) => ( <CarouselItem key={i} className="basis-1/3">{/* slide */}</CarouselItem> ))} </CarouselContent> <CarouselPrevious /> <CarouselNext /></Carousel>API
Carousel
| Prop | Type | Default | Description |
|---|---|---|---|
orientation | "horizontal" | "vertical" | "horizontal" | Scroll direction. |
opts | EmblaOptionsType | — | Forwarded to Embla. Common: align, loop, slidesToScroll. |
plugins | EmblaPluginType[] | — | Embla plugins (autoplay, fade, etc.). |
setApi | (api: EmblaCarouselType) => void | — | Receive the Embla instance for advanced control. |
CarouselContent / CarouselItem / CarouselPrevious / CarouselNext accept native attributes; the prev / next are styled <Button> instances.
Design guidelines
✓ Do
- Use Carousel only when horizontal motion adds something — e.g., constrained vertical space.
- Show prev / next controls. Don't rely on swipe alone — desktop has no swipe.
- Pair with a slide indicator (dots) when there are 5+ slides.
✗ Don't
- Auto-rotate. The user is not a billboard. If you must, never on a settings or content page.
- Use Carousel for lists the user could pick from — that's a list / table / grid.
- Loop infinitely without a clear "first" anchor. Users get disoriented.
Accessibility
- Embla provides
role="region" aria-roledescription="carousel"; items arerole="group" aria-roledescription="slide". - Prev / Next are real
<Button>instances.<Tab>reaches them; Enter activates. - Auto-rotation must be paused on focus / hover (Embla autoplay plugin handles this; verify before shipping).