Skip to content
Redpanda UI
Esc
↑↓navigate↵open⌘Jpreview
Made by shadcn
Edit on GitHub

Carousel

A carousel with motion and swipe built using Embla.

Installation

bash
npx shadcn@latest add @redpanda/carousel
bash
pnpm dlx shadcn@latest add @redpanda/carousel
bash
yarn dlx shadcn@latest add @redpanda/carousel
bash
bunx shadcn@latest add @redpanda/carousel
bash
nubx shadcn@latest add @redpanda/carousel
bash
aube dlx shadcn@latest add @redpanda/carousel

Usage

Carousel displays a scrollable, swipeable collection of slides with previous/next controls and keyboard arrow navigation.

tsx
import {  Carousel,  CarouselContent,  CarouselItem,  CarouselNext,  CarouselPrevious,} from '@/components/redpanda-ui/carousel';
tsx
<Carousel>  <CarouselContent>    <CarouselItem>...</CarouselItem>    <CarouselItem>...</CarouselItem>    <CarouselItem>...</CarouselItem>  </CarouselContent>  <CarouselPrevious />  <CarouselNext /></Carousel>

Anatomy

plaintext
Carousel Structure:┌─────────────────────────────────────────────────────┐│ <Carousel> (region, keyboard navigation)            ││ ┌─────────────────────────────────────────────────┐ ││ │ <CarouselContent> (scroll viewport)             │ ││ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ ││ │ │<CarouselItem>│ │<CarouselItem>│ │<CarouselItem>│ │ ││ │ │  (slide)    │ │  (slide)    │ │  (slide)    │ │ ││ │ └─────────────┘ └─────────────┘ └─────────────┘ │ ││ └─────────────────────────────────────────────────┘ ││  <CarouselPrevious />            <CarouselNext />    │└─────────────────────────────────────────────────────┘

Slot Guidelines

CarouselContent

Purpose: The scroll viewport that holds all slides.

Best practices:

  • Set gap="sm" or gap="md" on Carousel to coordinate track and item spacing. The default is md (16px); sm is 4px.
  • For vertical carousels, set an explicit viewport height (for example, h-50).
tsx
<Carousel gap="sm">  <CarouselContent>    <CarouselItem>...</CarouselItem>  </CarouselContent></Carousel>

CarouselItem

Purpose: A single slide. Has role="group" and aria-roledescription="slide".

Best practices:

  • Use basis-* utilities to control how many slides are visible at once
  • Keep slide content self-contained; avoid nested pressables inside clickable slides
tsx
{  /* 33% of the carousel width */}<CarouselItem className="basis-1/3">...</CarouselItem>;

CarouselPrevious / CarouselNext

Purpose: Navigation buttons. They render the registry Button and accept all of its props (variant, size, testId, …). They disable automatically when the carousel cannot scroll further.

tsx
<CarouselPrevious variant="ghost" /><CarouselNext variant="ghost" />

Props

Prop Type Default Description
opts CarouselOptions - Embla options
plugins CarouselPlugin - Embla plugins such as Autoplay
gap 'sm' | 'md' 'md' Coordinated slide spacing: 4px or 16px
orientation 'horizontal' | 'vertical' 'horizontal' Scroll axis
setApi (api: CarouselApi) => void - Receives the Embla API instance for imperative control
testId string - Sets data-testid for testing

Options

Options are passed to Embla via the opts prop:

tsx
<Carousel  opts={{    align: 'start',    loop: true,  }}>  ...</Carousel>

API

Use the setApi prop with CarouselApi state to listen to events and control the carousel imperatively:

tsx
import { Carousel, type CarouselApi } from '@/components/redpanda-ui/carousel';
function Example() {  const [api, setApi] = useState<CarouselApi>();
  useEffect(() => {    if (!api) {      return;    }
    api.on('select', () => {      // Do something on select    });  }, [api]);
  return <Carousel setApi={setApi}>...</Carousel>;}

Plugins

Plugins such as Autoplay are passed via the plugins prop:

tsx
import Autoplay from 'embla-carousel-autoplay';
<Carousel plugins={[Autoplay({ delay: 2000 })]}>...</Carousel>;

Examples

Basic

Sizes

Use the basis-* utility on <CarouselItem /> to size slides.

Vertical

Set orientation="vertical" and give <CarouselContent /> an explicit height.

With API

Accessibility

  • The carousel root has role="region" and aria-roledescription="carousel"
  • Each slide has role="group" and aria-roledescription="slide"
  • Left/Right arrow keys scroll to the previous/next slide when focus is inside the carousel
  • Navigation buttons include screen-reader-only labels and disable when scrolling is not possible

Credits

Recent changes

  • patchv1.2.0Pin shipped dependency floors to the version we develop against. Registry items now declare ranges like `^5.1.9` (the actual installed version) instead of collapsing to `^5.0.0`, so consumers start on the known-tested baseline while caret semantics still allow any compatible release within the same major.#133
  • minorv1.1.0Theme docs refresh, readability pass on semantic foregrounds, and consumer-facing Base UI regression fixes.#121
  • minorv1.0.0Post-Base-UI polish. Public API unchanged.#116
  • majorv1.0.0Migrate every Radix-based primitive to `@base-ui/react@^1.4.0` (Base UI).#114
  • minorv0.3.0Add theme-provider component to the registry with documentation and tests. Includes playground type improvements (export RegistryItem, remove as-const boilerplate) and docs site dark mode border color fix.#109
See full history →

Last updated on

Was this page helpful?