<!-- Generated by scripts/gen-docs.mts from the JSDoc in registry/. Do not edit; run `pnpm run docs`. -->

# AspectRatio

A frame that keeps an image, video or map at a fixed shape while its width follows the layout, so the page does not jump when the media loads. The media fills it and is cropped to fit.

```tsx
import { AspectRatio } from "@/components/ouro/aspect-ratio/aspect-ratio";
```

## Example

```tsx
<AspectRatio ratio={16 / 9}>
  <img src={recipe.coverUrl} alt={recipe.title} />
</AspectRatio>
```

## Use instead when

- Use `Card` with `media` instead for a photo at the top of a card (put the AspectRatio in `media`), and `Item` with `media` for a thumbnail beside a row's title.

## Props

Type: `AspectRatioProps`.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `children` (required) | `ReactNode` |  | The media: one `<img>`, `<video>`, `<iframe>` or element, which fills the frame. Give an image `alt` text, or `alt=""` when it is decoration. |
| `className` | `string` |  | Layout only: width, margins, grid placement (`w-40`). Appearance classes warn in development; put the frame in a `Card` for rounded corners. |
| `fit` | `"cover" \| "contain"` | `"cover"` | How an image or video fills the frame: `cover` crops it to fill, `contain` shows all of it with bars. |
| `ratio` (required) | `number \| (string & { "Use a number: ratio={16 / 9}": never })` |  | Width divided by height, as a number: `16 / 9` for video, `4 / 3` for a photo, `1` for a square. The frame is as wide as its container and this much shorter. |
| `ref` | `Ref<HTMLDivElement>` |  | Reaches the rendered element. |

## Native attributes

Also accepts the attributes in React's `HTMLAttributes` (`id`, `aria-*`, event handlers), passed to the rendered element, except those named on this page.

## Don't use

These are not props. Passing one fails the type check with the fix in the error, and in development a console message names the fix.

- `aspectRatio`: Not a prop. Ouro UI uses `ratio`: `<AspectRatio ratio={16 / 9}>`.

## `className` is for layout only

Pass margins, width and grid placement (`mt-4`, `w-full`, `col-span-2`). Your classes always win over Ouro UI's: AspectRatio merges `className` last with `cn` (tailwind-merge), so a class that conflicts with its own replaces it.[^layout-classes]

Appearance comes from props, not classes. In development, a class that sets appearance logs one warning per component instance, naming the prop to use instead. A class sets appearance when, after its variants (`hover:`, `sm:`) and any `!` are removed, it starts with `bg-`, `text-`, `border-`, `rounded-`, `shadow-`, `font-`, `ring-`, `from-`, `via-`, `to-`, `fill-` or `stroke-`, or is `border`, `rounded`, `shadow` or `ring`, or has a `dark:` variant. Text wrapping, overflow and table layout classes (`text-wrap`, `text-ellipsis`, `border-collapse`) are layout and do not warn.

Alignment classes (`text-center`) warn too: set alignment on a parent element.

[^layout-classes]: test:registry/ouro/components/ouro/aspect-ratio/aspect-ratio.test.tsx::AspectRatio > passes attributes and a ref through, and lets layout classes win verify:testExists(registry/ouro/components/ouro/aspect-ratio/aspect-ratio.test.tsx::AspectRatio > passes attributes and a ref through, and lets layout classes win)
