Carousel
Slide and snap content with keyboard, drag, and pointer support, built on Embla Carousel.
<Carousel className="w-full"> <CarouselContent> {Array.from({ length: 5 }).map((_, index) => ( <CarouselItem key={index} className="md:basis-1/2 lg:basis-1/3"> <Card> <CardContent className="flex aspect-square items-center justify-center p-6"> <Heading as="span" size="3xl" weight="semibold"> {index + 1} </Heading> </CardContent> </Card> </CarouselItem> ))} </CarouselContent> <CarouselPrevious /> <CarouselNext /></Carousel>Usage
import {
Carousel,
CarouselContent,
CarouselItem,
CarouselNext,
CarouselPrevious,
} from "@reva/ui";Carousel is built on Embla Carousel and uses Reva's IconButton for CarouselPrevious / CarouselNext (the upstream shadcn size="icon-sm" is mapped to IconButton size="sm"). Pass Embla options via opts, register plugins via plugins, and switch axis with orientation="vertical".
Composition
Use the following composition to build a Carousel:
Carousel
├── CarouselContent
│ ├── CarouselItem
│ ├── CarouselItem
│ └── CarouselItem
├── CarouselPrevious
└── CarouselNextExamples
Sizes
Set per-slide width with basis-* utilities on CarouselItem to show multiple items at once.
<Carousel opts={{ align: "start" }} className="w-full"> <CarouselContent> {Array.from({ length: 5 }).map((_, index) => ( <CarouselItem key={index} className="md:basis-1/2 lg:basis-1/3"> <Card> <CardContent className="flex aspect-square items-center justify-center p-6"> <Heading as="span" size="3xl" weight="semibold"> {index + 1} </Heading> </CardContent> </Card> </CarouselItem> ))} </CarouselContent> <CarouselPrevious /> <CarouselNext /></Carousel>Loop
Pass opts={{ loop: true }} to wrap from the last slide back to the first.
<Carousel opts={{ loop: true }} className="w-full"> <CarouselContent> {Array.from({ length: 5 }).map((_, index) => ( <CarouselItem key={index} className="md:basis-1/2 lg:basis-1/3"> <Card> <CardContent className="flex aspect-square items-center justify-center p-6"> <Heading as="span" size="3xl" weight="semibold"> {index + 1} </Heading> </CardContent> </Card> </CarouselItem> ))} </CarouselContent> <CarouselPrevious /> <CarouselNext /></Carousel>Autoplay
Pair with the embla-carousel-autoplay plugin and forward onMouseEnter / onMouseLeave to pause on hover.
import Autoplay from "embla-carousel-autoplay";function CarouselAutoplayDemo() { const plugin = React.useRef(Autoplay({ delay: 2000, stopOnInteraction: true })); return ( <Carousel plugins={[plugin.current]} className="w-full" onMouseEnter={plugin.current.stop} onMouseLeave={() => plugin.current.play()} > <CarouselContent> {Array.from({ length: 5 }).map((_, index) => ( <CarouselItem key={index} className="md:basis-1/2 lg:basis-1/3"> <Card> <CardContent className="flex aspect-square items-center justify-center p-6"> <Heading as="span" size="3xl" weight="semibold"> {index + 1} </Heading> </CardContent> </Card> </CarouselItem> ))} </CarouselContent> <CarouselPrevious /> <CarouselNext /> </Carousel> );}Vertical
Set orientation="vertical" to slide along the y-axis. Constrain CarouselContent height so the rail is tall enough to scroll.
<Carousel orientation="vertical" opts={{ align: "start" }} className="w-full"> <CarouselContent className="h-[280px]"> {Array.from({ length: 5 }).map((_, index) => ( <CarouselItem key={index} className="basis-1/2"> <Card> <CardContent className="flex h-full items-center justify-center p-6"> <Heading as="span" size="2xl" weight="semibold"> {index + 1} </Heading> </CardContent> </Card> </CarouselItem> ))} </CarouselContent> <CarouselPrevious /> <CarouselNext /></Carousel>Props
Carousel (root)
| Prop | Type | Default | Description |
|---|---|---|---|
orientation | "horizontal" | "vertical" | "horizontal" | Slide axis. Vertical mode requires a height constraint on CarouselContent. |
opts | EmblaOptionsType | — | Forwarded to Embla. See the options reference. |
plugins | EmblaPluginType[] | — | Embla plugin instances such as Autoplay, ClassNames, or custom plugins. |
setApi | (api: CarouselApi) => void | — | Receives the Embla API once initialized — use to drive carousel state from outside. |
className | string | — | Merged onto the root region wrapper. |
CarouselContent / CarouselItem
Plain div wrappers — accept className for layout adjustments. Use Tailwind basis-* utilities on CarouselItem to control per-slide width.
CarouselPrevious / CarouselNext
Render Reva IconButtons with data-slot="carousel-previous" / data-slot="carousel-next". Inherit IconButton props (variant, size, className); defaults are variant="outline" and size="sm".