Layout/Carousel

Carousel

A carousel with motion and swipe built using Embla.

Themed

When to Use

Use Carousel when you need to:

  • Display a sequence of images, cards, or content in a limited space
  • Create product galleries, testimonial sliders, or feature tours
  • Show multiple items that can be browsed one-at-a-time or in groups
  • Present media-rich content with swipe and drag interaction on touch devices
  • Build hero banners or promotional content rotators

When Not to Use

  • Long scrollable lists - use Scroll Area instead
  • Tabbed content where all sections are equally important - use Tabs
  • Expandable/collapsible content sections - use Accordion
  • Critical content that must be seen by all users - carousels hide content behind interaction

Default

Basic carousel with numbered slides and previous/next navigation.

1
2
3
4
5

With Images

Full-width image slides using AspectRatio for consistent 16:9 sizing.

Coastal landscape
City street at night
Coffee and pastry
Abstract gradient
Mountain forest

Image Cards

Multiple image cards with titles displayed in a multi-item layout using basis classes.

Coastal landscape
Image 1
Coastal landscape
City street at night
Image 2
City street at night
Coffee and pastry
Image 3
Coffee and pastry
Abstract gradient
Image 4
Abstract gradient
Mountain forest
Image 5
Mountain forest

Sizes

Control how many items are visible at once using Tailwind basis utility classes on CarouselItem.

1
2
3
4
5

Spacing

Customize gap between slides using pl-* on items and -ml-* on content.

1
2
3
4
5

Vertical

Vertical orientation with up/down scroll navigation. Set a fixed height on CarouselContent.

1
2
3
4
5

UX & Design Guidelines

Visual Hierarchy

Keep carousel content visually consistent across slides. Use bg-card with border-border for slide containers. Navigation buttons use variant="outline" by default to remain unobtrusive while still discoverable. Add dot indicators or slide counts for orientation context.

Spacing & Layout

The default gap between items is pl-4 (1rem). For tighter layouts, override with pl-1 on items and -ml-1 on CarouselContent. Navigation buttons are positioned -left-12 and -right-12, so ensure adequate horizontal padding on the parent container (at least px-12).

Responsive Behavior

Use responsive basis classes like md:basis-1/2 lg:basis-1/3 on CarouselItem to show more slides on larger screens. On mobile, default to full-width slides (basis-full). Touch and swipe interactions work automatically via Embla. Consider hiding navigation arrows on touch devices where swipe is intuitive.

Content & Media

Always use AspectRatio for image carousels to prevent layout shift. Use object-cover with fill on next/image for responsive images. Limit carousel to 8-10 slides maximum; beyond that, users rarely navigate to later items. For auto-playing carousels, provide a visible pause control and stop on user interaction.

Accessibility

Keyboard Navigation

  • ArrowLeft — Scroll to the previous slide
  • ArrowRight — Scroll to the next slide
  • Tab — Move focus to navigation buttons and interactive content within slides
  • Enter or Space — Activate the focused navigation button

Screen Reader Support

  • The carousel container has role="region" and aria-roledescription="carousel"
  • Each slide has role="group" and aria-roledescription="slide"
  • Navigation buttons include sr-only labels ("Previous slide" and "Next slide")
  • Disabled state is announced when first/last slide is reached (non-loop mode)

Focus Management

Arrow key events are captured at the container level via onKeyDownCapture, ensuring keyboard navigation works when any element within the carousel is focused. Navigation buttons use visible focus rings with focus-visible:ring-[3px] inherited from the Button component.

Touch & Pointer

Embla provides native drag-to-scroll on both touch and pointer devices. Navigation buttons are 32px (size-8) round targets, meeting minimum touch target recommendations. Buttons are automatically disabled at scroll boundaries to prevent no-op interactions.

ARIA Attributes

{/* Container with carousel role */}
<Carousel aria-label="Product gallery">
  <CarouselContent>
    {/* Each slide has role="group" and aria-roledescription="slide" */}
    <CarouselItem aria-label="1 of 5">
      ...
    </CarouselItem>
  </CarouselContent>

  {/* Navigation buttons have built-in sr-only labels */}
  <CarouselPrevious />
  <CarouselNext />
</Carousel>

{/* Auto-playing carousel with pause control */}
<Carousel
  plugins={[Autoplay({ delay: 3000, stopOnInteraction: true })]}
  aria-label="Featured announcements"
  aria-live="off"
>
  ...
</Carousel>

API Reference

The Carousel system is composed of five parts. The main container accepts the following props in addition to standard div attributes.

Carousel

Main container with Embla integration and keyboard navigation.

PropTypeDefaultDescription
optsEmblaOptionsTypeEmbla carousel options including align, loop, dragFree, and skipSnaps.
orientation"horizontal" | "vertical""horizontal"The scroll axis of the carousel.
setApi(api: EmblaCarouselType) => voidCallback to receive the Embla carousel API instance for programmatic control.
pluginsEmblaPluginType[]Embla plugins such as Autoplay, AutoScroll, or ClassNames.
classNamestringAdditional CSS classes to apply to the carousel container.

CarouselContent

Scrollable flex container that wraps all slides.

PropTypeDefaultDescription
classNamestringCSS classes for the scrollable flex container. Use -ml-* to adjust item spacing.

CarouselItem

Individual slide wrapper with role="group" semantics.

PropTypeDefaultDescription
classNamestringCSS classes for sizing (basis-1/2, basis-1/3) and spacing (pl-*).
childrenReactNodeThe content of the carousel slide.

CarouselPrevious / CarouselNext

Absolutely-positioned navigation buttons. Accept all Button props.

PropTypeDefaultDescription
variant"default" | "outline" | "ghost" | "secondary""outline"The visual style variant of the navigation button.
size"default" | "sm" | "lg" | "icon""icon"The size of the navigation button.
classNamestringAdditional CSS classes for positioning or styling the navigation button.