Shadcn Aspect Ratio for React and Tailwind
Wrapper that maintains aspect ratio for content.
Installation
bunx --bun shadcn@latest add https://kit.dev/r/aspect-ratio.jsonpnpm dlx shadcn@latest add https://kit.dev/r/aspect-ratio.jsonnpx shadcn@latest add https://kit.dev/r/aspect-ratio.jsonyarn shadcn@latest add https://kit.dev/r/aspect-ratio.jsonInstall the following dependencies:
bun add @ark-ui/reactpnpm add @ark-ui/reactnpm install @ark-ui/reactyarn add @ark-ui/reactCopy and paste the following code into your project.
"use client";
import { ark } from "@ark-ui/react/factory";
import type React from "react";
import { cn } from "@/lib/utils";
interface AspectRatioProps extends React.ComponentProps<typeof ark.div> {}
export const AspectRatio = (props: AspectRatioProps) => {
const { className, ...rest } = props;
return (
<ark.div
className={cn(
"[--ratio:1]",
"relative",
"w-full min-w-0",
"aspect-(--ratio)",
className
)}
data-slot="aspect-ratio"
{...rest}
/>
);
};Update the import paths to match your project setup.
Anatomy
A single wrapper. Put media or other content inside.
AspectRatio
└── content (img, video, iframe, …)Usage
import { AspectRatio } from "@/components/ui/aspect-ratio";<AspectRatio className="overflow-hidden rounded-xl [--ratio:16/9]">
<img
alt="Description"
className="size-full object-cover"
src="/image.jpg"
/>
</AspectRatio>The box is relative w-full with aspect-ratio: var(--ratio). Children that should fill it typically use size-full object-cover. Add overflow-hidden when you round corners on images or video.
Examples
Square
Portrait
Video
Responsive
Use [--ratio:*] with breakpoints to change the ratio at different screen sizes.
You can use breakpoint utilities to change the aspect ratio at different screen sizes.
sm:[--ratio:16/9] md:[--ratio:1/1]Common ratios: 1/1 (square), 16/9 (video), 4/3, 3/2, 9/16 (portrait).
API Reference
asChild merges props onto a single child element.
AspectRatio
Root. Renders a div. Width is w-full min-w-0; height comes from aspect-ratio: var(--ratio).
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | false | Merge onto a single child (for example figure or a). |
className | string | - | Class names on the root. Set [--ratio:…] here. |
| Attribute | Description |
|---|---|
data-slot | aspect-ratio |
| CSS variable | Default | Description |
|---|---|---|
--ratio | 1 | Used as aspect-ratio: var(--ratio). Write CSS ratios (16/9), not decimals, unless you want 1.777. |
There is no ratio React prop. Override the variable:
<AspectRatio className="[--ratio:4/3]" />Accessibility
This is a layout wrapper, not a widget. Put accessible names on the content:
- Images:
alt(emptyalt=""if decorative) - iframes / embeds:
title - Clickable
asChildlinks: visible text oraria-label
Keyboard support
The wrapper is not interactive. If asChild renders a link or button, it uses that element's keyboard behavior (Enter, Tab).