Reserves a fixed width-to-height ratio for media and embeds so the layout stays put while they load.
Description
AspectRatio is a single-element wrapper rendered as a <div>. It wraps Radix's AspectRatio.Root and forces its single child to fit a width-to-height ratio you specify via the ratio prop.
Reach for it when a media slot must reserve space before its asset paints. Typical cases: image thumbnails in lists and grids, video and iframe embeds (YouTube, Vimeo, Loom), and hero media on cards. Locking the slot prevents layout shift when the asset finally loads.
Don't use AspectRatio for text content that should wrap naturally, or as a generic flex / grid sizer. If the child already has a known intrinsic size (a fixed SVG icon, a sized button), skip it. If the layout only needs a minimum height, reach for Tailwind sizing utilities directly.
Installation
Usage
Examples
Landscape
ratio={16 / 9} is the default media aspect. Use it for video thumbnails, hero images, and any photo-first card cover.
Square
ratio={1} keeps width and height equal. Reach for it on product tiles, gallery grids, and avatar-style media.
Portrait
ratio={9 / 16} flips the slot vertical. Use it for mobile stories, reels, and any vertical video preview.
Common ratios
The design system catalogues a set of named ratios. Any positive number works for the ratio prop, but these are the canonical values used across the library:
The list is a convention, not a constraint. Pass any positive number you need, including custom values like ratio={1920 / 1080}.
Accessibility
AspectRatio is a passive layout primitive. It renders a plain <div> and has no keyboard interactions or focus behavior; the consumer is responsible for labelling the child media.
ARIA notes:
- The component sets no implicit role. Treat it as a layout box, not as semantic structure.
- Label the child, not the wrapper:
alton<img>,titleon<iframe>, anaria-labelon the video container when no caption is visible. - For purely decorative media, add
aria-hidden="true"on the child so assistive tech skips it. - Built on Radix's
AspectRatioprimitive. See Radix's docs for primitive-level behavior.
Styling
Tailwind override: pass className to merge Tailwind classes with the component's base classes (via cn()):
Data slots and attributes: the component sets these for CSS targeting:
data-slot="aspect-ratio"on the root<div>.- The component sets no
data-*state or variant attributes; there is no CVA axis to expose.
Target the slot directly in CSS:
Related Components
- Avatar: when the media is specifically a circular user portrait.
- Card: when the surface chrome (border, padding, radius) is the goal and the aspect is a side effect.
- Skeleton: when reserving space for non-media content (text lines, blocks) before data loads.
API Reference
AspectRatio
Reserves a fixed width-to-height ratio for its single child. Wraps Radix's AspectRatio.Root, so it accepts any standard <div> attribute (id, role, aria-*, onClick, etc.) plus Radix's primitive props.