Drivn vs shadcn/ui — Aspect Ratio Component Compared
Side-by-side comparison of Drivn and shadcn/ui React Aspect Ratio components — runtime deps, native CSS, API shape, ratio presets, and default behavior.
Pick either library's AspectRatio and the rendered box looks the same: content locked to a width-to-height ratio that holds at every viewport size. The difference sits behind the import. shadcn/ui's file is a forwardRef wrapper over @radix-ui/react-aspect-ratio, so installing it adds a Radix primitive package to your dependency tree. Drivn's file is fifteen lines of plain React that writes style={{ aspectRatio: ratio }} onto a div and stops there — no primitive, no ref forwarding, nothing to version-bump.
That structural gap shows up in three places you will notice while writing code. The ratio prop is typed differently: shadcn takes a number, Drivn takes '16/9' | '4/3' | '1/1' | number, so the three common ratios autocomplete as string literals. The default differs: omit the prop in Drivn and you get '16/9'; omit it in shadcn and nothing enforces a ratio. And the container ships different classes — Drivn bakes in relative w-full overflow-hidden, which means absolutely-positioned overlays anchor without an extra wrapper.
Below: dependency footprint, both prop APIs side by side, how children lay out inside each container, and where browser support actually lands in 2026. Code in every section comes from the shipped source of both libraries.
Side-by-side comparison
| Feature | Drivn | shadcn/ui |
|---|---|---|
| Runtime UI dependencies | None (React + Tailwind) | @radix-ui/react-aspect-ratio primitive |
| Ratio prop type | "16/9" | "4/3" | "1/1" | number | number |
| Default ratio | "16/9" | None (required on every instance) |
| String presets | ||
| Implementation | Inline style + native CSS aspect-ratio | Radix primitive via forwardRef |
| Container classes | relative w-full overflow-hidden | None by default |
| Absolute-child overlays | Ready (relative by default) | Needs extra wrapper |
| Source size | ≈15 lines, no primitive | Wrapper + Radix primitive |
| License | MIT | MIT |
| Copy-paste install |
API side-by-side
shadcn/ui exports AspectRatio from @/components/ui/aspect-ratio, a thin forwardRef wrapper around the Radix UI primitive at @radix-ui/react-aspect-ratio. You pass a ratio prop as a numeric expression — typically 16 / 9 or 4 / 3 — and any children render inside the ratio-locked container. Drivn exports the same name from the same path, but the file behind it is a single React function component with no forwardRef and no primitive import. The aspect ratio docs show the full API and props table.
Both libraries accept the same shape at the call site — <AspectRatio ratio={...}><img /></AspectRatio> — so migration in either direction is largely a find-and-replace on the import path. What diverges is the behavior when the ratio prop is omitted, the accepted type of that prop, and the dependency graph each component drags along at install time.
1 // shadcn/ui — wraps Radix primitive, numeric ratio 2 import { AspectRatio } from '@/components/ui/aspect-ratio' 3 4 <AspectRatio ratio={16 / 9}> 5 <img src="/hero.jpg" alt="Hero" className="h-full w-full object-cover" /> 6 </AspectRatio> 7 8 // Drivn — no runtime deps, string preset or number 9 import { AspectRatio } from '@/components/ui/aspect-ratio' 10 11 <AspectRatio ratio="16/9"> 12 <img src="/hero.jpg" alt="Hero" className="w-full h-full object-cover" /> 13 </AspectRatio>
Runtime dependencies
shadcn/ui's AspectRatio depends on @radix-ui/react-aspect-ratio, a Radix UI primitive that adds roughly two kilobytes gzipped on top of React once included. The primitive itself is small and well-maintained, but it arrives through the wider Radix dependency graph that also pulls in @radix-ui/react-primitive and a handful of shared utility packages used across every other Radix component you might have installed.
Drivn's AspectRatio depends on nothing outside of React and your existing Tailwind setup. The whole component file is fifteen lines — an interface declaration, a single function body, and an inline style that writes the aspect-ratio CSS property directly. No primitive, no forwardRef, no ref polyfill. If you open the component file after running the Drivn CLI, the source reads top to bottom without any framework abstraction. For a team that audits every runtime dependency, the difference is one fewer package in package.json and one fewer version bump to track.
The ratio prop API
shadcn/ui's ratio prop is typed as number, so you pass an arithmetic expression at every call site — ratio={16 / 9}, ratio={4 / 3}, or ratio={1} for a square. The expression is readable once and becomes repetitive noise when echoed across a media gallery, a video grid, or a list of thumbnail cards. There is no default; leave the prop off and you get a container with no enforced ratio at all.
Drivn's ratio prop accepts either a string preset ("16/9", "4/3", "1/1") or a raw number for non-standard ratios such as 2.35 for cinemascope. The preset form is a string literal union, so TypeScript autocompletes the three common ratios at every call site, and the component falls back to "16/9" if you omit the prop entirely. The numeric form is still available when you need a custom ratio — the React AspectRatio examples show both forms in context.
Neither API is objectively better. The numeric shape matches how designers think about ratios in Figma; the string preset matches how the underlying CSS aspect-ratio value actually reads in browser devtools. Pick the shape your team already uses in design specs.
1 // shadcn/ui — always a number, no default 2 <AspectRatio ratio={16 / 9}>{content}</AspectRatio> 3 <AspectRatio ratio={4 / 3}>{content}</AspectRatio> 4 <AspectRatio ratio={1}>{content}</AspectRatio> 5 6 // Drivn — string preset (defaults to "16/9"), or custom number 7 <AspectRatio>{content}</AspectRatio> 8 <AspectRatio ratio="4/3">{content}</AspectRatio> 9 <AspectRatio ratio="1/1">{content}</AspectRatio> 10 <AspectRatio ratio={2.35}>{content}</AspectRatio>
Container model and children
Both libraries put children inside a block container whose ratio comes from the native CSS aspect-ratio property, so an image with w-full h-full object-cover or an iframe with explicit fill dimensions behaves identically in either one. The divergence is what else that container carries. Drivn's div ships with relative w-full overflow-hidden already applied through cn(), merged with whatever className you pass; shadcn's wrapper sets no layout classes of its own.
Those three classes remove boilerplate in the layouts that actually reach for a ratio box. relative lets a caption bar, a play-button overlay, or a hover gradient sit as a direct absolutely-positioned child with no wrapper in between. overflow-hidden clips a scaled-up image on hover to the box edge instead of letting it bleed across neighboring cards. w-full makes the box fill its grid or flex track by default, which is what a media grid wants anyway. With shadcn you add each of these per instance or wrap the component once yourself. Overriding them stays clean either way, because cn() runs tailwind-merge — className="w-auto" on a fixed-width thumbnail wins over the baked-in w-full. The aspect ratio docs list the full prop and class surface.
1 // Drivn — the entire component, verbatim 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 }
Browser support and legacy engines
Both components lean on the native CSS aspect-ratio property, supported across every evergreen browser and roughly 94% of global traffic in 2026 per caniuse.com. For any product whose audience runs Chrome, Safari, Firefox, Edge, or their mobile counterparts from the last four years, either library works with zero fallback considerations at all.
Historically, Radix's aspect-ratio primitive shipped a padding-bottom percentage fallback for browsers that predated the native property. Modern @radix-ui/react-aspect-ratio has simplified to use the native property directly, so shadcn's behavior matches Drivn's on today's engines. Neither library gives you a polyfill for browsers from before 2022 — Internet Explorer 11 or early Android WebViews on legacy devices — out of the box.
Because Drivn's component lives in your repo after the CLI install, adding a padding-bottom fallback for a specific legacy audience is a five-line edit inside src/components/ui/aspect-ratio.tsx. That kind of surgical tweak is harder with shadcn because the fallback logic, if it returned, would need to be patched inside the Radix primitive.
Install Drivn in one command
Copy the source into your project and own every line. Zero runtime dependencies, pure React + Tailwind.
npx drivn@latest createRequires Node 18+. Works with npm, pnpm, and yarn.
Frequently asked questions
Migrate if you want to drop the @radix-ui/react-aspect-ratio package from your dependency tree, prefer a default ratio baked into the component, or want the convenience of string presets like "16/9" instead of arithmetic expressions at every call site. Stay on shadcn if you already use several Radix primitives and prefer one consistent wrapper style across the library, or if your team finds ratio={16 / 9} more explicit at the call site. The rendered output is identical on 2026 browsers, so the choice is about API taste and dependency footprint rather than visual behavior.
The native aspect-ratio CSS property covers roughly 94% of global traffic in 2026 — all modern Chrome, Safari, Firefox, and Edge builds. If your audience includes Internet Explorer 11 or legacy Android WebViews, neither Drivn nor shadcn ships a polyfill in the default install. You would add a padding-bottom percentage fallback by editing the component file after install — five additional lines inside src/components/ui/aspect-ratio.tsx — and because the source lives in your repo, the change survives every future update.
Pass a raw number to the ratio prop — ratio={21 / 9} or the equivalent 2.33. The string preset form only covers the three most common ratios ("16/9", "4/3", "1/1") because a union with every imaginable ratio would pollute the autocomplete surface. For cinemascope (2.35), ultrawide (21 / 9), or portrait video (9 / 16), the numeric form is the right fit and TypeScript will not complain because number is part of the prop's union type.
Yes. Drivn's container ships with relative and overflow-hidden Tailwind classes baked in, so any child with position: absolute anchors to the ratio box automatically. A typical pattern is an image as the first child with w-full h-full object-cover, followed by an overlay div positioned absolutely at the bottom with padding and a gradient background. shadcn's wrapper does not set relative by default, so the equivalent layout needs an extra wrapper div or a custom className on every instance.
Yes. Render <Image fill /> as the child and it fills the ratio-locked container automatically. The parent's native aspect-ratio CSS gives fill its box dimensions without any extra wrapper, so the pattern is a two-element stack — AspectRatio on the outside, Image fill on the inside. Set sizes on the Image for correct responsive srcset handling. The same two-element pattern also works with the shadcn version once you pass a numeric ratio prop.

