How to Add an Aspect Ratio Box to a React App
Step-by-step guide to adding a copy-and-own Aspect Ratio box to any React app with the Drivn CLI — string presets, custom ratios, zero runtime dependencies.
Locking content to a fixed shape sounds like a one-line CSS task until you ship it. An image arrives and the page reflows. A YouTube embed loads at the wrong height. A gallery of thumbnails looks square on desktop and stretched on mobile. The old padding-bottom percentage trick works but reads like a riddle six months later, and reaching for a headless library to avoid it adds a runtime dependency for something the browser can now do natively.
Drivn takes the direct route. The CLI writes an Aspect Ratio source file straight into your repo — no runtime UI package, no Radix primitive, no resize observer. The whole component is about fifteen lines: a single div with relative w-full overflow-hidden and an inline aspect-ratio style derived from a ratio prop. It accepts three string presets — "16/9", "4/3", "1/1" — or any raw number, and defaults to "16/9" so most media boxes need no prop at all. This guide adds it to an existing React app in roughly ten minutes: install the CLI, copy the component, render it on a page, and tune the ratio and container to match your layout.
You can follow along with a Vite + React project, a Next.js App Router app, Remix, or any React framework that supports Tailwind and TypeScript. The steps are identical. For setup context see the installation page; for the App Router variant see the Next.js Aspect Ratio guide; for live patterns see the Aspect Ratio examples page.
Prerequisites
Before installing the Aspect Ratio box, confirm your React project has the three things Drivn assumes: Tailwind CSS v4 installed and processing your styles, TypeScript configured (the component ships as a .tsx file), and a @/ path alias pointing at your source directory. Projects scaffolded with create-next-app, npm create vite, or npx drivn@latest create have all three wired up already. For a custom setup, check the compilerOptions.paths entry in your tsconfig.json; the installation page lists the minimal config. Unlike most Drivn components, Aspect Ratio reads no color tokens and renders no icon, so there is nothing to theme and no lucide-react to install — it is pure React and Tailwind from the first line.
Step 1 — Install Drivn via the CLI
Run the CLI from your project root to add the Aspect Ratio source file. The command prompts once for your install directory, defaulting to src/components/ui/, then writes aspect-ratio.tsx. No package is added to your package.json and no global config file is created — the component is just a TypeScript file in your repo that you edit like any other. The CLI docs cover the --cwd and --dir flags for monorepos or non-standard layouts. Once the file lands you own it; future Drivn releases will not overwrite it, so any change you make is permanent. Commit the change to keep a clean baseline before customizing.
1 # add the Aspect Ratio box to your existing React project 2 npx drivn add aspect-ratio
Step 2 — Import and render the box
Open the page where the media box should appear and import AspectRatio from your UI directory. The API is a single component with one meaningful prop — ratio — and your media as children. Because the default ratio is "16/9", you can omit the prop entirely for the most common case, a widescreen video or hero image. Style the child to fill the box with w-full h-full object-cover for images, or w-full h-full for iframes. The component holds no state, so it renders identically on the server and the client and works inside server components and static pages alike. See the Aspect Ratio docs for the full prop table and the examples page for video, portrait, and square patterns.
1 import { AspectRatio } from '@/components/ui/aspect-ratio' 2 3 export function HeroMedia() { 4 return ( 5 <AspectRatio ratio="16/9"> 6 <img 7 src="/hero.jpg" 8 alt="Product hero" 9 className="w-full h-full object-cover rounded-lg" 10 /> 11 </AspectRatio> 12 ) 13 }
Step 3 — Use presets or a custom ratio
The ratio prop is a string-literal union of three presets — "16/9", "4/3", "1/1" — plus number, so TypeScript autocompletes the common shapes at every call site while still allowing anything custom. Pass "1/1" for a square gallery tile, "4/3" for classic photo framing, or a raw number for non-standard proportions: ratio={2.35} for a cinematic crop, ratio={9 / 16} for a portrait reel, or ratio={width / height} computed from real dimensions. Whatever you pass is written straight into the inline aspectRatio CSS property, so any valid ratio works without editing the component. The value resolves before any media loads, which is what removes the layout shift an unsized image would otherwise cause.
1 // String presets — autocompleted by TypeScript 2 <AspectRatio ratio="16/9">{media}</AspectRatio> 3 <AspectRatio ratio="4/3">{media}</AspectRatio> 4 <AspectRatio ratio="1/1">{media}</AspectRatio> 5 6 // Custom numbers for anything else 7 <AspectRatio ratio={2.35}>{media}</AspectRatio> 8 <AspectRatio ratio={9 / 16}>{media}</AspectRatio>
Step 4 — Customize the container
Because the Aspect Ratio box lives in your codebase, customization is a source edit, not a prop workaround. The component merges your className over its base relative w-full overflow-hidden classes through cn, so you can add rounded corners, a border, or a placeholder background on any instance without touching the source. To restyle every box at once — say, a default rounded-xl across the app — edit the base string in src/components/ui/aspect-ratio.tsx directly. The relative base means absolutely-positioned children like caption overlays or play buttons anchor inside the ratio box automatically, and overflow-hidden clips any oversized media to the box edge. The theming page covers the design tokens you would reference for a placeholder color.
1 // src/components/ui/aspect-ratio.tsx 2 export function AspectRatio({ 3 ratio = '16/9', 4 className, 5 children, 6 }: AspectRatioProps) { 7 return ( 8 <div 9 className={cn('relative w-full overflow-hidden', className)} 10 style={{ aspectRatio: ratio }} 11 > 12 {children} 13 </div> 14 ) 15 }
Install Drivn in one command
Copy the source into your project and own every line. Zero runtime dependencies, pure React + Tailwind.
Frequently asked questions
Yes. Set up your CRA project with TypeScript and Tailwind v4 first, then run the Drivn CLI. The component has no dependency on React Router, Next.js, or any framework-specific API — it renders anywhere React and Tailwind render to the DOM. It also reads no color tokens and ships no icon, so unlike some Drivn components there is nothing to rename or install after copying the source.
None. The component imports only React and the local cn class-merge helper — there is no Radix primitive, no resize-observer polyfill, and no icon library. It sets its proportion with the native CSS aspect-ratio property rather than measuring the DOM, so the entire file is about fifteen lines. The CLI writes that single self-contained .tsx file into your project and your bundle grows by nothing more than its size.
Pass a raw number to the ratio prop — ratio={2.35} for cinemascope, ratio={9 / 16} for portrait video, or ratio={width / height} derived from known dimensions. The string presets ("16/9", "4/3", "1/1") cover the three most common shapes for autocomplete, while number is part of the same prop union for everything else. The value is written directly into the inline aspectRatio style, so any valid CSS aspect ratio works without changing the source.
Yes. Because the ratio resolves through the native CSS aspect-ratio property before any media loads, the container reserves its final height from first paint. An image, iframe, or video that arrives later fills the reserved space instead of pushing surrounding content down, which removes the cumulative layout shift an unsized <img> or embed would otherwise cause. Pair it with a matching ratio for the asset and the box never reflows.

