Keeps a box at a fixed width-to-height ratio and stretches its child to fill it — an iframe, a video, a map, an image or a placeholder. Pure CSS aspect-ratio, server-safe, no layout shift.
Installation
The whole kit as one package — get updates by bumping the version. Add the styles to globals.css: @import "@vamos-ui/react/styles.css";
Usage
import { AspectRatio } from "@vamos-ui/react";
<AspectRatio ratio="16/9" rounded="ui-lg">
<iframe src="https://player.example.com/embed/7421" title="Product tour" />
</AspectRatio>For images use Image with aspect — it also handles srcset, focal point and placeholders. AspectRatio is for everything else.
Nothing is focusable on the box itself; keyboard and screen readers reach the child directly.
Examples
Ratios
"1/1", "4/5", "4/3", "16/9", "21/9" or any number. The width follows the container.
Embedded map (site)
The direct child is positioned to fill the box; iframes lose their default border. tone="inset" shows surface-2 while it loads.
Video player (course page)
A <video> keeps 16:9 at every width; fit sets its object-fit.
API
AspectRatio
| Prop | Type | Default |
|---|---|---|
ratioWidth ÷ height. Strings also accept "16:9". Invalid values fall back to 16/9. | "16/9" | "4/3" | `${number}/${number}` | number | "16/9" |
roundedCorner radius from --radius; the child is clipped. | "none" | "ui" | "ui-lg" | "full" | "none" |
fitobject-fit for a direct <img> or <video>. | "cover" | "contain" | "fill" | "cover" |
toneinset: a surface-2 backdrop (letterboxing, loading iframes). | "none" | "inset" | "none" |
childrenOne element; it is stretched to fill the box. | ReactNode | — |
Helpers
| Prop | Type | Default |
|---|---|---|
parseAspectRatio(ratio)"16/9" → 1.777…, "4:3" → 1.333…, 1.5 → 1.5. | → number | undefined | — |