Carousel
Paged content on the marketing surfaces: one engine, composable parts.
The brand weaves
Overview
Built on Embla, because a marketing carousel has to feel like a gesture and not a slideshow: real drag physics on touch, momentum, and slides that settle rather than snap. Embla supplies the engine; everything it looks like comes from here.
import {
Carousel,
CarouselContent,
CarouselItem,
CarouselNext,
CarouselPrevious,
} from "@rogo-technologies/brand/carousel";
<Carousel opts={{ loop: true }}>
<CarouselContent>
{slides.map((slide) => (
<CarouselItem key={slide.id}>{slide.content}</CarouselItem>
))}
</CarouselContent>
<CarouselPrevious />
<CarouselNext />
</Carousel>;The provider carries the engine and the parts read it from context, so a surface composes exactly
the frame and controls it needs: controls beside a headline, under the track, or wherever the
band puts them. Never inside a CarouselItem: a control that rides a slide travels with it and is
gone mid-press.
| Part | What it is |
|---|---|
Carousel | The provider. opts passes to Embla; setApi hands the engine out. |
CarouselContent | The scrolling track inside its clipping viewport. |
CarouselItem | One slide. Size it with a basis-* class; basis-full is the default. |
CarouselPrevious | The back disc. Disabled at the start unless loop is on. |
CarouselNext | The forward disc. Disabled at the end unless loop is on. |
useCarousel | The context, for custom controls or progress indicators. |
Slide rhythm
Embla expects the gap to live on the slides: give each CarouselItem a pl-* and mirror it as a
negative margin on CarouselContent, so the first slide sits flush while every pair keeps the gap.
<CarouselContent className="-ml-5">
<CarouselItem className="basis-[62%] pl-5">…</CarouselItem>
</CarouselContent>Bleeding off the page
A track that runs to the screen's edge says there is more to page through. Keep the viewport at full width and walk the first slide in with padding that matches the page shell, the way the landing page's case-study wall does:
<CarouselContent
viewportClassName="w-full"
className="pl-5 tablet:pl-10 wide:pl-[max(40px,calc((100vw-1280px)/2))]"
>Keyboard and announcement
The region is announced as a carousel, each item as a slide, and the arrow keys page it. That comes with the provider, not from the controls, so it holds even when a surface draws its own.