# Carousel

> A row of slides with previous/next buttons and dots.

Component · Media · Pro kit · [Live page](https://ui.twentyfirst.media/pro/components/Carousel/)

A row of slides with previous/next buttons and dots. Swipe or scroll on touch, ←/→ on the keyboard.

- `perView` shows several slides on wide screens; phones always show one (with a peek of the next).
- `loop` wraps around at the ends.
- The carousel is a labelled region; each slide is announced as "n of total".

## Example

```tsx
import { Carousel, ProductArt } from "@twentyfirstmedia/pro";

const ITEMS = [
  ["tee", "sky", "Halo Cotton Tee", "€32"],
  ["mug", "butter", "Studio Mug", "€18"],
  ["bottle", "mint", "Field Bottle", "€28"],
  ["tote", "lilac", "Canvas Tote", "€24"],
  ["cap", "blush", "Trail Cap", "€22"],
] as const;

export default function Preview() {
  return (
    <div className="tf-col" style={{ gap: 32 }}>
      <Carousel
        label="Featured products"
        perView={3}
        slides={ITEMS.map(([k, t, name, price]) => (
          <div key={k} className="tf-card" style={{ minHeight: 0, gap: 8 }}>
            <ProductArt kind={k} tint={t} />
            <b>{name}</b>
            <span className="tf-card-desc">{price}</span>
          </div>
        ))}
      />
      <Carousel
        label="Onboarding"
        loop
        slides={["Invite your team", "Connect your mailbox", "Approve your first draft"].map(
          (t, i) => (
            <div
              key={t}
              className="tf-panel"
              style={{
                minHeight: 160,
                justifyContent: "center",
                alignItems: "center",
                textAlign: "center",
              }}
            >
              <span className="tf-card-desc">Step {i + 1} of 3</span>
              <b style={{ fontSize: 20 }}>{t}</b>
            </div>
          ),
        )}
      />
    </div>
  );
}
```

## Props

### Carousel

| Prop | Type | Notes |
| --- | --- | --- |
| `slides` | `ReactNode[]` | Required |
| `label` | `string` | Accessible name of the carousel. |
| `perView?` | `number` | Slides visible at once on wide screens (1 on phones). |
| `loop?` | `boolean` | Next on the last slide goes back to the first. |
| `dots?` | `boolean` | Dots under the slides. |
| `index?` | `number` |  |
| `defaultIndex?` | `number` |  |
| `onChange?` | `(index: number) => void` |  |
| `className?` | `string` | Extra class on the root element. |
| `style?` | `CSSProperties` | Inline style on the root element. |

### ProductArt

| Prop | Type | Notes |
| --- | --- | --- |
| `kind` | `ArtKind` | Required |
| `tint?` | `Tint \| "plain"` |  |
| `size?` | `number` |  |
| `label?` | `string` |  |
| `className?` | `string` | Extra class on the root element. |
| `style?` | `CSSProperties` | Inline style on the root element. |
