Elements
Media carousel
View in FigmaStateful media carousel with full-bleed slides, dot controls, and an optional caption slot.
Install
npx shadcn@latest add @alix/mediaCarouselPreview

Operations review
Images, controls, and caption content stay in one composed section.
Usage
<MediaCarousel ariaLabel="Operations review images" media={media}>
<TextTileDefault
bgColor="default"
sectionTitle={{
title: "Operations review",
description: "Images, controls, and caption content stay together.",
align: "start",
}}
buttonGroup={{}}
/>
</MediaCarousel>Examples
01
Single slide
A single media item keeps the same frame and caption slot while hiding carousel controls.

Project controls review
A single image can still share the carousel layout when more media may arrive later.
<div className="w-full max-w-2xl">
<MediaCarousel
ariaLabel="Site review image"
media={[
{
src: "/brand/construction.webp",
alt: "Construction site with cranes",
},
]}
ratio="4/3"
bgColor="secondary"
>
<TextTileDefault
bgColor="transparent"
sectionTitle={{
title: "Project controls review",
description: "A single image can still share the carousel layout when more media may arrive later.",
align: "start",
}}
buttonGroup={{}}
leftBorder
/>
</MediaCarousel>
</div>02
Flipped caption
Flip the order when the copy should introduce the media before the user reaches the slides.

Client workshop
The controls stay attached to the media even when the caption moves above the slide frame.
<div className="w-full max-w-3xl">
<MediaCarousel
ariaLabel="Client workshop images"
media={media}
bgColor="primary"
flip
>
<TextTileDefault
bgColor="transparent"
sectionTitle={{
title: "Client workshop",
description: "The controls stay attached to the media even when the caption moves above the slide frame.",
align: "start",
}}
buttonGroup={{}}
leftBorder
/>
</MediaCarousel>
</div>03
Panel media review
Put the carousel inside a flush Panel when media review sits in a dashboard workspace.
Operational walkthrough
Images reviewed in the weekly steering meeting

Steering evidence
Panel chrome names the workspace while the carousel owns slide state and controls.
<div className="w-full max-w-3xl">
<Panel
title="Operational walkthrough"
description="Images reviewed in the weekly steering meeting"
flush
>
<MediaCarousel
ariaLabel="Operational walkthrough images"
media={media}
bgColor="default"
>
<TextTileDefault
bgColor="transparent"
sectionTitle={{
title: "Steering evidence",
description: "Panel chrome names the workspace while the carousel owns slide state and controls.",
align: "start",
}}
buttonGroup={{}}
leftBorder
/>
</MediaCarousel>
</Panel>
</div>When to use it
Use it for
- Image sets where previous, next, and dot controls should stay attached to the media frame.
- Composed media sections where the caption can be any React node, often a TextTile.
- Single-slide states that may grow into a carousel without changing the surrounding layout.
Reach for something else
- Static hero or banner imagery — use MediaBanner instead.
- A single framed image with no caption or controls — use AspectRatio instead.
- CMS-ready multimedia sections with locked layout choices — use MultimediaBlock instead.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| media | MediaContent[] | — | Image or video slide data, discriminated by type; an empty array renders nothing. |
| ratio | AspectRatioToken | "16/9" | Aspect ratio for every slide frame. |
| bgColor | BgColor | "default" | Section surface behind the controls and caption; media remains full-bleed. |
| flip | boolean | false | Mirrors caption and media order while keeping controls attached to the media. |
| ariaLabel | string | — | Required accessible name for the carousel region. |
| children | ReactNode | — | Caption slot rendered beside the controls, not a shadow API for a text tile. |

