Aspect Ratio
StableHolds media to a fixed width-to-height ratio, reserving its space before the content loads.
Installation
$ pnpm dlx shadcn@latest add https://www.prfct.dev/r/aspect-ratio.jsonUsage
import { AspectRatio } from "@/components/ui/aspect-ratio"<AspectRatio ratio={16 / 9} className="overflow-hidden rounded-xl">
<img src="/cover.jpg" alt="…" className="size-full object-cover" />
</AspectRatio>ratio is width divided by height. The component is a positioned <div> sized with the CSS aspect-ratio property — no JavaScript, no padding hacks — so it works in server components and never shifts after hydration.
Examples
Common ratios
Choose the ratio from the content, then keep it consistent across a collection so grids line up.
With Next.js Image
Use fill so the image takes the box's size, and object-cover to crop instead of stretching. Pass sizes so the browser downloads the right resolution.
import Image from "next/image"
<AspectRatio ratio={16 / 9} className="overflow-hidden rounded-xl bg-muted">
<Image
src="/showcase/dashboard.png"
alt="The analytics dashboard in dark mode"
fill
sizes="(min-width: 768px) 50vw, 100vw"
className="object-cover"
/>
</AspectRatio>Video
Video and embeds should reserve their frame before they load. Overlay controls and metadata with absolute positioning — the box is already relative.
<AspectRatio ratio={16 / 9} className="overflow-hidden rounded-xl">
<iframe
src="https://www.youtube-nocookie.com/embed/…"
title="Designing with tokens"
allow="accelerometer; encrypted-media; picture-in-picture"
allowFullScreen
className="absolute inset-0 size-full"
/>
</AspectRatio>Square grid
A 1:1 ratio keeps avatars, product shots and thumbnails uniform even when the source images aren't.
- Ana
- Jonas
- Maya
- Theo
- Iris
- Lena
- Omar
- Eli
Card media
Put the ratio box first in a card with pt-0 on the card, and the media runs edge to edge with the card's rounded corners.
Guidelines
When to use
- For images, video, maps and embeds whose container width changes with the layout.
- In grids and carousels, to keep every tile the same shape.
- Wherever late-loading media would otherwise push content down.
When not to use
- For text or UI whose height depends on its content — fixing the ratio will clip or leave gaps.
- When the container already has fixed pixel dimensions; set them directly.
Crop, don't distort
Media inside a ratio box should use object-cover (crop to fill) or object-contain (letterbox), never the default stretch.
Accessibility
Aspect Ratio is purely presentational; what matters is the media inside it.
- Images need
alttext that says what the image shows, oralt=""when it's decorative. - Video needs captions, and embeds need a
titlethat names the content. - Layout stability. Reserving space prevents content from jumping as media loads, which helps everyone — and especially people using magnification or reading slowly.
API reference
AspectRatio
Renders a <div> with position: relative and aspect-ratio set from ratio. Accepts every <div> prop.