A scrollable content area with previous/next navigation and keyboard support.
A composable carousel built on Embla Carousel. Supports horizontal and vertical orientations, plugins, and exposes the underlying API for advanced use cases.
import {
Carousel,
CarouselContent,
CarouselItem,
CarouselNext,
CarouselPrevious,
} from "@/components/ui/carousel"
export default function CarouselDemo() {
return (
<Carousel className="w-full max-w-xs">
<CarouselContent>
{Array.from({ length: 5 }).map((_, index) => (
<CarouselItem key={index}>
<div className="flex aspect-square items-center justify-center rounded-md border p-6">
<span className="text-4xl font-semibold">{index + 1}</span>
</div>
</CarouselItem>
))}
</CarouselContent>
<CarouselPrevious />
<CarouselNext />
</Carousel>
)
}
import {
Carousel,
CarouselContent,
CarouselItem,
CarouselPrevious,
CarouselNext,
} from "@/components/ui/carousel"<Carousel>
<CarouselContent>
<CarouselItem>Slide 1</CarouselItem>
<CarouselItem>Slide 2</CarouselItem>
<CarouselItem>Slide 3</CarouselItem>
</CarouselContent>
<CarouselPrevious />
<CarouselNext />
</Carousel><Carousel>
<CarouselContent>
{Array.from({ length: 5 }).map((_, i) => (
<CarouselItem key={i}>
<div className="flex aspect-square items-center justify-center rounded-md border text-4xl font-semibold">
{i + 1}
</div>
</CarouselItem>
))}
</CarouselContent>
<CarouselPrevious />
<CarouselNext />
</Carousel>Use the basis utility on CarouselItem to show multiple slides at once.
<Carousel>
<CarouselContent>
{items.map((item) => (
<CarouselItem key={item} className="basis-1/3">
<Card>{item}</Card>
</CarouselItem>
))}
</CarouselContent>
<CarouselPrevious />
<CarouselNext />
</Carousel><Carousel orientation="vertical" className="max-h-64">
<CarouselContent>
<CarouselItem>Slide 1</CarouselItem>
<CarouselItem>Slide 2</CarouselItem>
<CarouselItem>Slide 3</CarouselItem>
</CarouselContent>
<CarouselPrevious />
<CarouselNext />
</Carousel>Use setApi to get access to the Embla Carousel API instance for programmatic control.
function Demo() {
const [api, setApi] = React.useState<CarouselApi>()
React.useEffect(() => {
if (!api) return
api.on("select", () => {
console.log("Current slide:", api.selectedScrollSnap())
})
}, [api])
return (
<Carousel setApi={setApi}>
<CarouselContent>
<CarouselItem>Slide 1</CarouselItem>
<CarouselItem>Slide 2</CarouselItem>
</CarouselContent>
</Carousel>
)
}The root component. Sets up the Embla Carousel instance and provides context to child components.
| Prop | Type | Default | Description |
|---|---|---|---|
orientation | "horizontal" | "vertical" | "horizontal" | The scroll direction. |
opts | CarouselOptions | — | Embla Carousel options. |
plugins | CarouselPlugin | — | Embla Carousel plugins. |
setApi | (api: CarouselApi) => void | — | Callback to receive the Embla API instance. |
className | string | — | |
children | ReactNode | — |
The scrollable container. Renders an overflow-hidden wrapper around a flex row (or column).
| Prop | Type | Default |
|---|---|---|
className | string | — |
children | ReactNode | — |
A single slide. Defaults to basis-full so each item takes the full carousel width.
| Prop | Type | Default |
|---|---|---|
className | string | — |
children | ReactNode | — |
A button that scrolls to the previous slide. Absolutely positioned to the left (or top in vertical mode).
| Prop | Type | Default | Description |
|---|---|---|---|
variant | ButtonVariant | "outline" | The button variant. |
size | ButtonSize | "icon-sm" | The button size. |
className | string | — |
A button that scrolls to the next slide. Absolutely positioned to the right (or bottom in vertical mode).
| Prop | Type | Default | Description |
|---|---|---|---|
variant | ButtonVariant | "outline" | The button variant. |
size | ButtonSize | "icon-sm" | The button size. |
className | string | — |