Embla-powered carousel with aspect-ratio presets and responsive navigation placement.
npx shadcn@latest add @iconiq/carousel"use client";
import {
Carousel,
CarouselContent,
CarouselItem,
CarouselNext,
CarouselPrevious,
} from "@/components/ui/carousel";
const slides = [
"Ship interfaces that feel polished from the first slide.",
"Motion, spacing, and type that stay in sync.",
"Drop in components—skip the layout guesswork.",
"Scroll stories without losing your rhythm.",
"Build faster. Keep the craft.",
] as const;
export function CarouselUsage() {
return (
<Carousel className="w-full max-w-md sm:max-w-lg">
<CarouselContent>
{slides.map((slide) => (
<CarouselItem key={slide}>
<div className="flex h-full items-center justify-center p-1">
<p className="px-6 text-center font-light text-lg leading-snug text-balance text-muted-foreground">
{slide}
</p>
</div>
</CarouselItem>
))}
</CarouselContent>
<CarouselPrevious />
<CarouselNext />
</Carousel>
);
}orientationSets the Embla scroll axis and the spacing applied between slides.
Type "horizontal" | "vertical"·Default horizontal
aspectRatioSets the slide viewport shape on `CarouselContent`. Use presets like `video` (16:9) and `square`, or pass a custom ratio string such as `21/9`.
Type "square" | "video" | "4/3" | "3/2" | "portrait" | string·Default video
navPlacementPositions previous and next controls. `responsive` places controls below the carousel on the right on mobile and outside the track from `sm` upward.
Type "outside" | "responsive"·Default responsive
autoplayWhen enabled, advances slides on a timer. Pass a number for the delay in milliseconds. Pair with `opts={{ loop: true }}` for continuous playback.
Type boolean | number
optsForwarded Embla options such as `align`, `loop`, or `slidesToScroll`. The root merges `axis` from `orientation`.
Type CarouselOptions
pluginsOptional Embla plugins passed to `useEmblaCarousel`, such as `embla-carousel-autoplay`.
Type CarouselPlugin
setApiOptional callback that receives the Embla API instance after mount for external index or dot indicators.
Type (api: CarouselApi) => void
aria-labelAccessible label for the root `role="region"` carousel wrapper.
Type string·Default Carousel
classNameOptional class names merged onto the root `role="region"` wrapper.
Type string
classNameOptional class names merged onto the inner flex container that holds slides.
Type string
classNameOptional class names merged onto each slide group.
Type string
classNameOptional class names merged onto the control for local offsets or sizing.
Type string
selectedIndexZero-based index of the active scroll snap.
Type number
scrollSnapCountTotal number of scroll snaps reported by Embla.
Type number
scrollToScrolls directly to the requested snap index.
Type (index: number) => void
scrollPrev / scrollNextMoves to the previous or next snap.
Type () => void
apiUnderlying Embla API instance when you need lower-level control.
Type CarouselApi
Install the exact registry entry shown on the right when you want the component file and its declared runtime dependencies together.
Dependencies: embla-carousel-react, lucide-react.
Navigation controls are built into the carousel file — no separate button install is required.
Built-in `autoplay` pauses after drag or manual navigation, then resumes after the configured delay. Pair with `opts={{ loop: true }}` for continuous playback.
Custom aspect ratios such as `21/9` are applied with inline `aspect-ratio` styles so Tailwind JIT does not need a safelist entry.
Default `navPlacement` is `responsive`: controls sit below the carousel on the right on mobile and outside from `sm` upward.
The generated registry file is /r/carousel.json.
Contact
Additionally, if you find any bug or issue, feel free to raise an issue.