Data display
Carousel
A horizontal slider for a small set of cards or previews, with arrow buttons, dots and keyboard support.
npx prodular-ui add carouselOne at a time
Release notes, one card per slide, with dots for position.
"use client"
import { Badge } from "@/components/ui/badge"import { Card, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"import { Carousel, CarouselContent, CarouselDots, CarouselItem, CarouselNext, CarouselPrevious,} from "@/components/ui/carousel"
const releases = [ { version: "v2.18", title: "Usage based pricing tiers", body: "Bill by API calls, seats or events with graduated tiers and a free allowance." }, { version: "v2.17", title: "Dunning emails in 9 languages", body: "Failed payment reminders now follow the customer's locale and your brand." }, { version: "v2.16", title: "Webhook retry dashboard", body: "See every failed delivery, inspect the payload and retry it in one click." }, { version: "v2.15", title: "Bulk credit notes", body: "Issue credit notes for up to 500 invoices at once from a CSV." },]
export default function CarouselDefault() { return ( <Carousel className="w-full max-w-sm"> <CarouselContent> {releases.map((r) => ( <CarouselItem key={r.version}> <Card className="h-full"> <CardHeader> <Badge variant="outline" size="sm" className="mb-1"> {r.version} </Badge> <CardTitle>{r.title}</CardTitle> <CardDescription>{r.body}</CardDescription> </CardHeader> </Card> </CarouselItem> ))} </CarouselContent> <CarouselPrevious /> <CarouselNext /> <CarouselDots /> </Carousel> )}Several per view
Set a basis on CarouselItem and align start to show a row of previews.
Minimal invoice2,410 workspaces
Itemized usage1,182 workspaces
Agency retainer860 workspaces
Annual contract744 workspaces
Marketplace payout391 workspaces
Credit note2,035 workspaces
"use client"
import { AspectRatio } from "@/components/ui/aspect-ratio"import { Carousel, CarouselContent, CarouselDots, CarouselItem, CarouselNext, CarouselPrevious,} from "@/components/ui/carousel"
const templates = [ { name: "Minimal invoice", uses: "2,410 workspaces" }, { name: "Itemized usage", uses: "1,182 workspaces" }, { name: "Agency retainer", uses: "860 workspaces" }, { name: "Annual contract", uses: "744 workspaces" }, { name: "Marketplace payout", uses: "391 workspaces" }, { name: "Credit note", uses: "2,035 workspaces" },]
export default function CarouselMultiple() { return ( <Carousel opts={{ align: "start" }} className="w-full max-w-xl"> <CarouselContent> {templates.map((t, i) => ( <CarouselItem key={t.name} className="basis-1/2 sm:basis-1/3"> <div className="flex flex-col gap-2"> <AspectRatio ratio={3 / 4} className="overflow-hidden rounded-lg border bg-card shadow-xs"> <div className="flex h-full flex-col gap-1.5 p-3"> <div className="h-2 w-10 rounded-full bg-brand-9" style={{ opacity: 0.25 + (i % 3) * 0.25 }} /> <div className="mt-2 h-1.5 w-3/4 rounded-full bg-muted" /> <div className="h-1.5 w-1/2 rounded-full bg-muted" /> <div className="mt-auto flex flex-col gap-1.5 border-t pt-2"> <div className="h-1.5 w-full rounded-full bg-muted" /> <div className="h-1.5 w-2/3 rounded-full bg-muted" /> </div> </div> </AspectRatio> <div className="flex flex-col"> <span className="text-sm font-medium">{t.name}</span> <span className="text-[13px] text-muted-foreground tabular-nums">{t.uses}</span> </div> </div> </CarouselItem> ))} </CarouselContent> <CarouselPrevious /> <CarouselNext /> <CarouselDots /> </Carousel> )}Anatomy
<Carousel> <CarouselContent> <CarouselItem>...</CarouselItem> </CarouselContent> <CarouselPrevious /> <CarouselNext /> <CarouselDots /></Carousel>Guidance
Use it when
- A short set of optional, browsable items: templates, release notes, onboarding tips.
- Previews where seeing a few at once is enough.
Avoid
- Content people must see. Items after the first are easy to miss.
- More than about ten items. Use a grid or a list.
- Autoplay. It moves content away while people read.
Rules for AI agents
Published in llms-full.txt and the registry, so coding agents follow them when they build with this component.
- Always include CarouselPrevious and CarouselNext. They sit outside the content, so leave about 48px of space on each side.
- Add CarouselDots when there are fewer than ten slides.
- For several items per view, set className="basis-1/2 sm:basis-1/3" on CarouselItem and opts={{ align: "start" }} on Carousel.
- Make slides the same height. Use h-full on the slide content.
- Do not add autoplay plugins unless the user asks for them.
API
Carousel
| Prop | Type | Default | Description |
|---|---|---|---|
| opts | EmblaOptionsType | Embla options such as align and loop. | |
| orientation | "horizontal" | "vertical" | "horizontal" | Scroll direction. |
| setApi | (api: CarouselApi) => void | Receives the Embla API for custom controls. |
CarouselItem
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | Set basis-* to show several items per view. |
CarouselDots
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | One dot per snap point. Hidden when there is only one. |