Aspect Ratio

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.

CSS aspect-ratio (no dependencies) components/aspect-ratio.tsxtheme · material · accent · density · font

Installation

$ pnpm add @vamos-ui/react

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.

1/1
4/5
4/3
16/9
21/9

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.

Northwind StudioHarbour Street 12, 3rd floorMon–Fri · 09:00–18:00

Video player (course page)

A <video> keeps 16:9 at every width; fit sets its object-fit.

Lesson 3 · Pricing your first workshop18 min

API

AspectRatio

PropTypeDefault
ratio
Width ÷ height. Strings also accept "16:9". Invalid values fall back to 16/9.
"16/9" | "4/3" | `${number}/${number}` | number"16/9"
rounded
Corner radius from --radius; the child is clipped.
"none" | "ui" | "ui-lg" | "full""none"
fit
object-fit for a direct <img> or <video>.
"cover" | "contain" | "fill""cover"
tone
inset: a surface-2 backdrop (letterboxing, loading iframes).
"none" | "inset""none"
children
One element; it is stretched to fill the box.
ReactNode—

Helpers

PropTypeDefault
parseAspectRatio(ratio)
"16/9" → 1.777…, "4:3" → 1.333…, 1.5 → 1.5.
→ number | undefined—