Skip to content
Drivn
6 min read

React Aspect Ratio Examples — Video, Image, Portrait

Copy-paste React Aspect Ratio examples — 16:9 video embed, responsive hero image, square avatar tile, portrait video clip, and Next.js Image integration.

Aspect ratio is the kind of CSS problem that reads as solved in a mockup and turns fiddly the moment real media loads. A container has to hold its shape whether the child is a 1920x1080 still, a YouTube iframe, a slow-loading hero, or a Next.js Image with fill. Get it wrong and the page jumps every time a picture finishes downloading, the crop shifts on mobile, or an overlay caption drifts a line away from where the designer pinned it in Figma.

Drivn's AspectRatio is deliberately small — a single div that takes a ratio prop and writes it straight to the native aspect-ratio CSS property. The prop accepts a string preset ("16/9", "4/3", "1/1") or any raw number like 2.35, and it defaults to "16/9" so hero images and video embeds need no prop at all. The wrapper carries relative w-full overflow-hidden, which means absolutely-positioned overlays anchor to the ratio box on their own and any oversized child is clipped cleanly at the edge.

This page collects five patterns you will actually ship: a default 16:9 video container, a responsive hero image, a square avatar tile, a portrait 9:16 reel clip, and the two-line Next.js Image fill integration. Every snippet is copy-paste and assumes Drivn is already installed via the CLI. For the engineering trade-offs against shadcn/ui's AspectRatio, see Drivn vs shadcn/ui AspectRatio.

Default 16:9 video embed

The single most common AspectRatio use is a 16:9 container for an embedded video — YouTube, Vimeo, Loom, Wistia, or a self-hosted <video> element. Drivn's default ratio is "16/9", so you can omit the prop entirely for this case. Children fill the container with w-full h-full, and the overflow-hidden default keeps any slight oversizing clipped cleanly to the ratio box edge.

Drop this snippet into a marketing page, a course lesson, or a product landing hero. Because the ratio is locked at 16:9, the iframe never triggers cumulative layout shift when it loads — the space is reserved by CSS before any JavaScript runs. The aspect ratio docs cover the full prop list and API reference.

1import { AspectRatio } from '@/components/ui/aspect-ratio'
2
3// Default ratio is "16/9" — the prop is optional
4<AspectRatio>
5 <iframe
6 src="https://www.youtube.com/embed/dQw4w9WgXcQ"
7 title="YouTube video"
8 className="w-full h-full"
9 allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
10 allowFullScreen
11 />
12</AspectRatio>

Responsive hero image

For a hero banner or landing-page image, pair AspectRatio with a single <img> styled w-full h-full object-cover. The object-cover rule ensures the image fills the ratio box and crops the overflow rather than distorting the pixels. Add rounded-lg or rounded-2xl on either the container or the child for rounded media cards that match your card component radius.

This pattern also works for responsive product images on e-commerce grids. Pair the 16/9 ratio with a max-width on the parent container and the image scales fluidly down to mobile without ever changing shape. The browser serves the right resolution through a srcset on the img tag if you configure one — nothing about AspectRatio is specific to srcset handling, so the usual HTML rules apply.

For a more advanced setup that layers a gradient and text overlay on top of the image, the container is already position: relative, so overlays anchor inside the ratio box without an extra wrapper div.

1<AspectRatio ratio="16/9">
2 <img
3 src="/hero.jpg"
4 alt="Team collaborating"
5 className="w-full h-full object-cover rounded-lg"
6 />
7</AspectRatio>

Square 1:1 avatar tile

Square tiles are everywhere once you start looking: profile galleries, team pages, product thumbnails, album artwork, Instagram-style grids. Reach for the "1/1" string preset — one of the three built-ins next to "16/9" and "4/3" — and drop each tile into a Tailwind grid so the layout stays square at every breakpoint. Inside each box the image renders w-full h-full object-cover, so cropping stays uniform no matter how the source photos were exported.

When the square specifically holds a user's face, Drivn's dedicated Avatar component is the better fit — it bundles rounded fallbacks, image loading states, and fixed size presets. Keep AspectRatio for square media that is not a person: catalog thumbnails, blog card covers, collection tiles, cover art. At runtime the DOM is the same single div either way; the choice is about signalling intent to the next developer who reads the code, not about visual output.

1<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
2 {images.map((img) => (
3 <AspectRatio key={img.id} ratio="1/1">
4 <img
5 src={img.url}
6 alt={img.alt}
7 className="w-full h-full object-cover rounded-lg"
8 />
9 </AspectRatio>
10 ))}
11</div>

Portrait 9:16 reel clip

Vertical video is now the default shape for short-form content — TikTok, Instagram Reels, YouTube Shorts, and Spotify Video all render at 9:16. AspectRatio handles this with a custom numeric ratio of 9 / 16, which resolves to 0.5625. You pass the division expression directly or the evaluated number, whichever reads better in the surrounding code.

Constrain the parent container to a maximum width around 320-400 pixels for a natural mobile-preview feel on desktop. Without the constraint, a 9:16 box becomes taller than most viewports and pushes subsequent page content far below the fold. The parent should also avoid overflow: hidden at the section level if you want the embedded player's fullscreen controls to escape the ratio box on user interaction.

For a gallery of reel clips, combine this ratio with a horizontal scroll container. The ScrollArea component gives you styled native scrollbars and snap-scrolling behavior without a third-party dependency.

1<div className="max-w-sm">
2 <AspectRatio ratio={9 / 16}>
3 <video
4 src="/reel.mp4"
5 className="w-full h-full object-cover rounded-xl"
6 controls
7 playsInline
8 />
9 </AspectRatio>
10</div>

Next.js Image with fill

Next.js's Image component gives you automatic srcset generation, blurhash placeholders, and lazy loading. Render it with the fill prop as a child of AspectRatio and the framework handles all the responsive sizing details. Set sizes to help Next.js pick the right resolution at each viewport width — a typical value for a hero image is "(max-width: 768px) 100vw, 50vw".

Because AspectRatio provides a container with explicit dimensions through the native aspect-ratio property, Image fill has a concrete box to fill. This pattern avoids the older trick of wrapping the image in a relative div with a padding-bottom hack; the ratio is enforced by CSS rather than by layout math. The rendered HTML stays minimal — two nested wrappers and the Next.js-generated <img> with its srcset.

See the Installation guide for how to set up next/image with Drivn, and the theming docs for how media cards in light and dark mode should tune their background placeholder colors before the image loads.

1import Image from 'next/image'
2import { AspectRatio } from '@/components/ui/aspect-ratio'
3
4<AspectRatio ratio="16/9">
5 <Image
6 src="/hero.jpg"
7 alt="Hero"
8 fill
9 sizes="(max-width: 768px) 100vw, 50vw"
10 className="object-cover rounded-lg"
11 />
12</AspectRatio>
Get started

Install Drivn in one command

Copy the source into your project and own every line. Zero runtime dependencies, pure React + Tailwind.

npx drivn@latest create

Requires Node 18+. Works with npm, pnpm, and yarn.

Enjoying Drivn?
Star the repo on GitHub to follow new component releases.
Star →

Frequently asked questions

The default is "16/9", set as the default value of the ratio prop inside src/components/ui/aspect-ratio.tsx. Change it by editing the default in the destructured prop signature — for instance to ratio = "4/3". Because the component file lives in your repo after install, the change is permanent and survives every future package update. Most teams keep the "16/9" default and override per call site when needed.

Functionally they are identical — AspectRatio writes the same aspect-ratio property to the container via inline style. The component exists to give you a consistent, typed API across your codebase, so every ratio-locked media box uses the same wrapper rather than scattered one-off class names. It also bakes in position: relative and overflow: hidden defaults that media containers usually want anyway.

Yes. The container is a block-level div with w-full, so it expands to fill the available width of its flex parent and then calculates height from the ratio. If the flex parent has align-items: stretch on a row layout, the AspectRatio will not grow vertically beyond its computed ratio. In a column layout with flex-grow set on a sibling, the AspectRatio stays at its ratio-derived height naturally.

Yes. A common pattern is an outer AspectRatio for a card tile with an inner AspectRatio for the card's thumbnail at a different ratio — for example a 4:3 card containing a 16:9 thumbnail above a title block. Each level has its own ratio prop and resolves independently. There is no performance cost to nesting; every instance is a single div with one inline style and three Tailwind utility classes.

Yes. The ratio is enforced by the aspect-ratio CSS property on the container, not by the children's intrinsic size. An empty AspectRatio still reserves its ratio-correct box, which is why the pattern works for skeleton loading states — render an empty container with a bg-muted class while the real content fetches, and the layout stays stable the moment the image or video slots in.