<!-- Generated by scripts/gen-docs.mts from the JSDoc in registry/. Do not edit; run `pnpm run docs`. -->

# Carousel

A row of slides the user swipes or steps through with Previous and Next buttons: recipe photos, a few featured cards. It is the browser's own scrolling with snap points, so swiping, trackpads and arrow keys all work and a vertical swipe still scrolls the page. Each child is a slide named "Slide 2 of 5", and moving to another slide announces that position politely, once. It never moves on its own, and with reduced motion the buttons jump instead of scrolling smoothly.

```tsx
import { Carousel } from "@/components/ouro/carousel/carousel";
```

## Example

```tsx
<Carousel label="Recipe photos">
  {photos.map((photo) => <img key={photo.id} src={photo.src} alt={photo.alt} />)}
</Carousel>
<Carousel label="Featured recipes" slidesPerView={2} loop onIndexChange={setIndex}>
  {recipes.map((recipe) => <RecipeCard key={recipe.id} recipe={recipe} />)}
</Carousel>
```

## Use instead when

- Use a grid instead when every item should be visible at once, and `Tabs` when the panels have names the user picks from.

## Props

Type: `CarouselProps`.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `children` (required) | `ReactNode` |  | The slides: each child is one slide, so pass the images or cards themselves. |
| `className` | `string` |  | Layout only: width and margins (`max-w-xl`, `mx-auto`). Appearance classes warn in development. |
| `defaultIndex` | `number` | `0` | The slide to start on, counting from 0. The starting slide is not announced. |
| `label` (required) | `string` |  | Names the carousel for screen readers, such as "Recipe photos". It is always required. |
| `loop` | `boolean` |  | Next on the last slide goes back to the first, and Previous on the first goes to the last. |
| `nextLabel` | `string` | `"Next slide"` | The Next button's accessible name. |
| `onIndexChange` | `((index: number) => void)` |  | Called with the index of the first visible slide when the user moves to another slide, once per change. |
| `previousLabel` | `string` | `"Previous slide"` | The Previous button's accessible name. |
| `roleDescription` | `string` | `"carousel"` | What a screen reader calls the carousel, after its label: "Recipe photos, carousel". |
| `slideLabel` | `string` | `"Slide {n} of {total}"` | Names each slide and is announced when the position changes: `{n}` is the slide's number and `{total}` the number of slides. |
| `slideRoleDescription` | `string` | `"slide"` | What a screen reader calls each slide, after its name: "Slide 2 of 5, slide". |
| `slidesPerView` | `1 \| 2 \| 3` | `1` | How many slides show at once. |

## Don't use

These are not props. Passing one fails the type check with the fix in the error, and in development a console message names the fix.

- `autoplay`: Not a prop. Carousel never moves on its own: motion the user did not start is hard to read and to stop.
- `opts`: Not a prop. Ouro UI's Carousel is not Embla: `<Carousel loop>`.
- `orientation`: Not a prop. Carousel scrolls horizontally; stack vertical content in a grid instead.
- `plugins`: Not a prop. Carousel never moves on its own, so it takes no plugins.
- `setApi`: Not a prop. Read the position with `onIndexChange`: `<Carousel onIndexChange={setIndex}>`.

## `className` is for layout only

Pass margins, width and grid placement (`mt-4`, `w-full`, `col-span-2`).

Appearance comes from props, not classes. In development, a class that sets appearance logs one warning per component instance, naming the prop to use instead. A class sets appearance when, after its variants (`hover:`, `sm:`) and any `!` are removed, it starts with `bg-`, `text-`, `border-`, `rounded-`, `shadow-`, `font-`, `ring-`, `from-`, `via-`, `to-`, `fill-` or `stroke-`, or is `border`, `rounded`, `shadow` or `ring`, or has a `dark:` variant. Text wrapping, overflow and table layout classes (`text-wrap`, `text-ellipsis`, `border-collapse`) are layout and do not warn.

Alignment classes (`text-center`) warn too: set alignment on a parent element.
