Carousel
A swipeable set of slides with previous and next controls.
1
2
3
4
5
import { Carousel, CarouselContent, CarouselItem, CarouselPrevious, CarouselNext } from '@/components/ui/carousel'
export default function CarouselDemo() {
return (
<Carousel className="w-full max-w-xs" aria-label="Numbered slides">
<CarouselContent>
{Array.from({ length: 5 }, (_, index) => (
<CarouselItem key={index} aria-label={`${index + 1} of 5`}>
<div className="flex aspect-square items-center justify-center rounded-lg border border-border bg-card p-6">
<span className="text-4xl font-semibold">{index + 1}</span>
</div>
</CarouselItem>
))}
</CarouselContent>
<CarouselPrevious />
<CarouselNext />
</Carousel>
)
}
Installation
pnpm dlx shadcn@latest add https://kagadmodyaa.vercel.app/r/carousel.jsonNeeds a React + Tailwind project set up with shadcn. Copies the component source straight into your project, so you can edit it.
Carousel imports cn() from lib/utils.ts — add it too if you don't have it yet:
import { clsx, type ClassValue } from 'clsx'
import { twMerge } from 'tailwind-merge'
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
Its previous and next controls are Buttons. The CLI installs Button for you; if you copy manually, add components/ui/button.tsx too.
Usage
import {
Carousel,
CarouselContent,
CarouselItem,
CarouselPrevious,
CarouselNext,
} from '@/components/ui/carousel'
<Carousel className="w-full max-w-xs" aria-label="Featured work">
<CarouselContent>
<CarouselItem>Slide 1</CarouselItem>
<CarouselItem>Slide 2</CarouselItem>
<CarouselItem>Slide 3</CarouselItem>
</CarouselContent>
<CarouselPrevious />
<CarouselNext />
</Carousel>
// Several at once: set a basis on each item
<CarouselItem className="basis-1/2 lg:basis-1/3">…</CarouselItem>
// Vertical: give the content a height
<Carousel orientation="vertical">
<CarouselContent className="h-72">…</CarouselContent>
</Carousel>Examples
Several slides at once
1
2
3
4
5
6
7
8
import { Carousel, CarouselContent, CarouselItem, CarouselPrevious, CarouselNext } from '@/components/ui/carousel'
export default function CarouselSizes() {
return (
<Carousel opts={{ align: 'start' }} className="w-full max-w-sm" aria-label="Slides, several at a time">
<CarouselContent>
{Array.from({ length: 8 }, (_, index) => (
<CarouselItem key={index} aria-label={`${index + 1} of 8`} className="basis-1/2 lg:basis-1/3">
<div className="flex aspect-square items-center justify-center rounded-lg border border-border bg-card p-4">
<span className="text-2xl font-semibold">{index + 1}</span>
</div>
</CarouselItem>
))}
</CarouselContent>
<CarouselPrevious />
<CarouselNext />
</Carousel>
)
}
Vertical
1
2
3
4
5
import { Carousel, CarouselContent, CarouselItem, CarouselPrevious, CarouselNext } from '@/components/ui/carousel'
export default function CarouselVertical() {
return (
<Carousel orientation="vertical" opts={{ align: 'start' }} className="w-full max-w-xs" aria-label="Vertical slides">
<CarouselContent className="h-[200px]">
{Array.from({ length: 5 }, (_, index) => (
<CarouselItem key={index} aria-label={`${index + 1} of 5`} className="basis-1/2">
<div className="flex h-full items-center justify-center rounded-lg border border-border bg-card p-4">
<span className="text-3xl font-semibold">{index + 1}</span>
</div>
</CarouselItem>
))}
</CarouselContent>
<CarouselPrevious />
<CarouselNext />
</Carousel>
)
}
API Reference
| Name | Type | Default | Description |
|---|---|---|---|
| orientation | 'horizontal' | 'vertical' | 'horizontal' | The scroll direction. A vertical carousel needs a height on CarouselContent. |
| opts | EmblaOptions | — | Embla's options: loop, align, slidesToScroll, dragFree, startIndex, and so on. |
| plugins | EmblaPlugin[] | — | Embla plugins, such as autoplay. |
| setApi | (api: CarouselApi) => void | — | Receives the Embla API — read the selected slide, listen for changes or scroll from your own controls. |
| aria-label | string | — | Names the carousel region for screen readers. Give each CarouselItem an aria-label such as "2 of 5" too. |
| CarouselItem className | string | — | Set the slide size with a basis class (basis-1/2, basis-1/3, …). One slide fills the view by default. |
| CarouselPrevious / CarouselNext | ButtonProps | — | Step buttons, disabled at either end (unless loop is on). Accept Button props such as variant. |
| Keyboard | — | — | With the carousel focused, ArrowLeft and ArrowRight (ArrowUp and ArrowDown when vertical) change slide. Drag or swipe also works. |
| Reduced motion | — | — | When the visitor prefers reduced motion, the buttons and arrow keys jump to the slide instead of scrolling. |