Slides in a row to swipe or step through, with arrows, dots, looping and autoplay.
$ pnpm dlx shadcn@latest add https://dashral.com/r/carousel.jsonInstallation
$ pnpm dlx shadcn@latest add https://dashral.com/r/carousel.jsonAdds the component, the components it builds on, its npm packages and the theme tokens it uses. Using Dashral often? Add the registry to components.json once:
{
"registries": {
"@dashral": "https://dashral.com/r/{name}.json"
}
}Then add components by name:
$ pnpm dlx shadcn@latest add @dashral/carouselUsage
import { Carousel } from "@/components/dashral/carousel"
<Carousel
items={products.map((product) => (
<img key={product.id} src={product.image} alt={product.name} className="rounded-lg" />
))}
perView={{ base: 1, md: 3 }}
label="Featured products"
/>Examples
Several at once
perView per screen size (1, 2, 3, then 4 across); controls="below" and indicator="count" put the arrows and “2 / 4” under the row.
Autoplay
autoplay moves on by itself and loops; it waits while you point at it, and Pause stops it. With text on the slides, controls="below" keeps the arrows off the words.
API reference
Carousel
Also takes every prop of <section>(opens in a new tab).
| Prop | Type | Default |
|---|---|---|
items | ReactNode[]The slides, in order. Required. | — |
perView | number | { base?, sm?, md?, lg?, xl? }Slides in view at once, or per screen size from the smallest up. | 1 |
gap | numberSpace between slides, in pixels. | 16 |
index / defaultIndex | numberThe first slide in view, from 0. | 0 |
onIndexChange | (index: number) => voidAnother slide comes first: arrows, dots, swiping, keys or autoplay. | — |
loop | booleanFrom the end, Next goes back to the start, and Previous the other way. | false |
autoplay | numberMoves on every this many ms and loops. Pauses on hover and focus, with a Pause button; starts paused with reduced motion. | — |
controls | "overlay" | "below" | "none"The arrows: over the edges (from sm), in a row under the slides, or none. | "overlay" |
indicator | "dots" | "count" | "none"Under the slides: a dot per position, “2 / 5”, or nothing. | "dots" |
label | stringNames it for screen readers, e.g. “Featured products”. | "Carousel" |
classNames | { viewport?, slide?, controls?, arrow? }Classes for each part. | — |
className | stringExtra classes, merged with cn() so yours win. | — |
Keyboard
| Keys | Action |
|---|---|
| Tab | Into the slides, then the arrows and dots |
| ←or→ | Previous / next slide (mirrored right to left) |
| HomeorEnd | First / last position |
Accessibility
- A section with aria-roledescription="carousel", named by label; each slide is a group read as “2 of 5”.
- The slide that comes in is announced, except while autoplay moves it; autoplay always has a Pause button and stops while you point at it or work in it.
- Arrows and dots are labelled buttons; the current dot has aria-current.
Motion
- Slides glide to their place with native smooth scrolling and snap; dragged with the mouse, the row follows the pointer and settles on the next slide when you let go. The current dot stretches on the spring. With reduced motion slides jump and autoplay starts paused.