Carousel
A horizontally (or vertically) scrolling set of slides. Thin Tidal wrapper around embla-carousel-react, following the shadcn composition.
Horizontal (default)
1
2
3
4
5
<Carousel opts={{ align: "start" }}>
<CarouselContent>
{items.map((i) => (
<CarouselItem key={i}>
<Slide>{i}</Slide>
</CarouselItem>
))}
</CarouselContent>
<CarouselPrevious />
<CarouselNext />
</Carousel>Multiple items per view
1
2
3
4
5
6
7
8
<Carousel opts={{ align: "start" }}>
<CarouselContent>
{items.map((i) => (
<CarouselItem key={i} className="basis-1/3">
<Slide>{i}</Slide>
</CarouselItem>
))}
</CarouselContent>
<CarouselPrevious />
<CarouselNext />
</Carousel>Vertical
1
2
3
4
5
<Carousel orientation="vertical" opts={{ align: "start" }}>
<CarouselContent className="h-[260px]">
{items.map((i) => (
<CarouselItem key={i} className="basis-1/2">
<Slide>{i}</Slide>
</CarouselItem>
))}
</CarouselContent>
<CarouselPrevious />
<CarouselNext />
</Carousel>Reading the API
1
2
3
4
5
Slide 1 of 0
const [api, setApi] = React.useState<CarouselApi>();
const [current, setCurrent] = React.useState(1);
const [count, setCount] = React.useState(0);
React.useEffect(() => {
if (!api) return;
setCount(api.scrollSnapList().length);
setCurrent(api.selectedScrollSnap() + 1);
api.on("select", () => setCurrent(api.selectedScrollSnap() + 1));
}, [api]);
<Carousel setApi={setApi}>…</Carousel>
<p>Slide {current} of {count}</p>Props
| Component | Notable props |
|---|---|
| Carousel | orientation ("horizontal" | "vertical"), opts (embla options), plugins, setApi |
| CarouselContent | Standard div props. Holds CarouselItems, receives embla viewport ref internally. |
| CarouselItem | Standard div props. basis-* controls per-view slide count. |
| CarouselPrevious | IconButton props. Defaults to variant="outline", size="md". |
| CarouselNext | IconButton props. Defaults to variant="outline", size="md". |
Source
packages/react/src/components/carousel.tsx · Figma node 2819:21463