Carousel
A slider to display multiple items in a scrollable view.
1
2
3
4
5
carousel-demo.tsx
import { AspectRatio } from "@/components/ui/aspect-ratio"
import {
Carousel,
CarouselContent,
CarouselItem,
CarouselNavigation,
CarouselNext,
CarouselPrevious,
} from "@/components/ui/carousel"
const slides = [1, 2, 3, 4, 5]
export function CarouselDemo() {
return (
<div className="w-60 sm:w-80 lg:w-96">
<Carousel>
<CarouselContent>
{slides.map((slide) => (
<CarouselItem key={slide}>
<AspectRatio
ratio={16 / 9}
className="rounded-lg border bg-background"
>
<div className="flex size-full items-center justify-center text-xl font-semibold text-foreground">
{slide}
</div>
</AspectRatio>
</CarouselItem>
))}
</CarouselContent>
<CarouselNavigation>
<CarouselPrevious />
<CarouselNext />
</CarouselNavigation>
</Carousel>
</div>
)
}
Installation
npx shadcn@latest add https://9ui.dev/r/carousel
Usage
Imports
import {
Carousel,
CarouselContent,
CarouselItem,
CarouselNavigation,
CarouselNext,
CarouselPrevious,
} from "@/components/ui/carousel"
Anatomy
<Carousel>
<CarouselContent>
<CarouselItem />
</CarouselContent>
<CarouselNavigation>
<CarouselPrevious />
<CarouselNext />
</CarouselNavigation>
</Carousel>
Examples
Vertical
1
2
3
4
5
carousel-vertical.tsx
import { AspectRatio } from "@/components/ui/aspect-ratio"
import {
Carousel,
CarouselContent,
CarouselItem,
CarouselNavigation,
CarouselNext,
CarouselPrevious,
} from "@/components/ui/carousel"
const slides = [1, 2, 3, 4, 5]
export function CarouselVertical() {
return (
<div className="w-60 sm:w-80 lg:w-96">
<Carousel orientation="vertical" options={{ loop: true }}>
<CarouselContent className="aspect-video h-[-webkit-fill-available] w-full p-1">
{slides.map((slide) => (
<CarouselItem key={slide} className="basis-full">
<AspectRatio
ratio={16 / 9}
className="rounded-lg border bg-background"
>
<div className="flex size-full items-center justify-center font-medium text-foreground">
{slide}
</div>
</AspectRatio>
</CarouselItem>
))}
</CarouselContent>
<CarouselNavigation className="bottom-0.5">
<CarouselPrevious />
<CarouselNext />
</CarouselNavigation>
</Carousel>
</div>
)
}
Multiple
1
2
3
4
5
carousel-multiple.tsx
import { AspectRatio } from "@/components/ui/aspect-ratio"
import {
Carousel,
CarouselContent,
CarouselItem,
CarouselNavigation,
CarouselNext,
CarouselPrevious,
} from "@/components/ui/carousel"
const slides = [1, 2, 3, 4, 5]
export function CarouselMultiple() {
return (
<div className="w-60 sm:w-80 lg:w-96">
<Carousel>
<CarouselContent>
{slides.map((slide) => (
<CarouselItem key={slide} className="basis-1/3">
<AspectRatio
ratio={16 / 9}
className="rounded-lg border bg-background"
>
<div className="flex size-full items-center justify-center text-xl font-semibold text-foreground">
{slide}
</div>
</AspectRatio>
</CarouselItem>
))}
</CarouselContent>
<CarouselNavigation>
<CarouselPrevious />
<CarouselNext />
</CarouselNavigation>
</Carousel>
</div>
)
}
Looped
1
2
3
4
5
carousel-looped.tsx
import { AspectRatio } from "@/components/ui/aspect-ratio"
import {
Carousel,
CarouselContent,
CarouselItem,
CarouselNavigation,
CarouselNext,
CarouselPrevious,
} from "@/components/ui/carousel"
const slides = [1, 2, 3, 4, 5]
export function CarouselLooped() {
return (
<div className="w-60 sm:w-80 lg:w-96">
<Carousel options={{ loop: true }}>
<CarouselContent>
{slides.map((slide) => (
<CarouselItem key={slide}>
<AspectRatio
ratio={16 / 9}
className="rounded-lg border bg-background"
>
<div className="flex size-full items-center justify-center text-xl font-semibold text-foreground">
{slide}
</div>
</AspectRatio>
</CarouselItem>
))}
</CarouselContent>
<CarouselNavigation>
<CarouselPrevious />
<CarouselNext />
</CarouselNavigation>
</Carousel>
</div>
)
}
Thumbnail
![Carousel slide](/_next/image?url=https%3A%2F%2Fimages.pexels.com%2Fphotos%2F1616403%2Fpexels-photo-1616403.jpeg%3Fauto%3Dcompress%26cs%3Dtinysrgb%26w%3D450%26h%3D800%26dpr%3D2&w=3840&q=75)
![Carousel slide](/_next/image?url=https%3A%2F%2Fimages.pexels.com%2Fphotos%2F1293120%2Fpexels-photo-1293120.jpeg%3Fauto%3Dcompress%26cs%3Dtinysrgb%26w%3D450%26h%3D800%26dpr%3D2&w=3840&q=75)
![Carousel slide](/_next/image?url=https%3A%2F%2Fimages.pexels.com%2Fphotos%2F1103970%2Fpexels-photo-1103970.jpeg%3Fauto%3Dcompress%26cs%3Dtinysrgb%26w%3D450%26h%3D800%26dpr%3D2&w=3840&q=75)
![Carousel slide](/_next/image?url=https%3A%2F%2Fimages.pexels.com%2Fphotos%2F2011824%2Fpexels-photo-2011824.jpeg%3Fauto%3Dcompress%26cs%3Dtinysrgb%26w%3D450%26h%3D800%26dpr%3D2&w=3840&q=75)
![Carousel slide](/_next/image?url=https%3A%2F%2Fimages.pexels.com%2Fphotos%2F2471235%2Fpexels-photo-2471235.jpeg%3Fauto%3Dcompress%26cs%3Dtinysrgb%26w%3D450%26h%3D800%26dpr%3D2&w=3840&q=75)
carousel-thumbnail.tsx
import { useState } from "react"
import Image from "next/image"
import { AspectRatio } from "@/components/ui/aspect-ratio"
import {
Carousel,
CarouselApi,
CarouselContent,
CarouselItem,
} from "@/components/ui/carousel"
const slides = [
"https://images.pexels.com/photos/1616403/pexels-photo-1616403.jpeg?auto=compress&cs=tinysrgb&w=450&h=800&dpr=2",
"https://images.pexels.com/photos/1293120/pexels-photo-1293120.jpeg?auto=compress&cs=tinysrgb&w=450&h=800&dpr=2",
"https://images.pexels.com/photos/1103970/pexels-photo-1103970.jpeg?auto=compress&cs=tinysrgb&w=450&h=800&dpr=2",
"https://images.pexels.com/photos/2011824/pexels-photo-2011824.jpeg?auto=compress&cs=tinysrgb&w=450&h=800&dpr=2",
"https://images.pexels.com/photos/2471235/pexels-photo-2471235.jpeg?auto=compress&cs=tinysrgb&w=450&h=800&dpr=2",
]
export function CarouselThumbnail() {
const [api, setApi] = useState<CarouselApi>()
return (
<div className="w-60 sm:w-80 lg:w-96">
<Carousel setApi={setApi}>
<CarouselContent>
{slides.map((slide) => (
<CarouselItem key={slide}>
<AspectRatio
ratio={16 / 9}
className="rounded-lg border bg-background"
>
<Image
src={slide}
alt="Carousel slide"
fill
className="rounded-lg object-cover"
/>
</AspectRatio>
</CarouselItem>
))}
</CarouselContent>
<div className="mt-2 flex items-center justify-center gap-2">
{slides.map((slide, index) => (
<button
key={slide}
className="relative size-10"
onClick={() => api?.scrollTo(index)}
>
<Image
src={slide}
alt="Carousel slide"
fill
className="rounded-md object-cover opacity-80 transition-opacity duration-200 hover:opacity-100"
/>
</button>
))}
</div>
</Carousel>
</div>
)
}