Surfaces
AspectRatio
A box that keeps its shape whatever is inside it.
Usage
When to reach for it
import { AspectRatio } from '@misoto22/design'Notes
A box that keeps its shape whatever is inside it.
The one layout primitive that is genuinely hard to hand-roll. The padding-
top: 56.25% trick everyone reaches for is a percentage of the WIDTH, which is why it works at all and also why it silently breaks the moment the box is a flex or grid child — and it takes the element's own padding with it. The modern aspect-ratio property does the same job in one line, and only holds if nothing inside forces a height, which is what the absolute positioning below guarantees.
So: the box declares the ratio, and every direct child is stretched to fill it and taken out of flow. That means a child with no intrinsic size at all — an empty <div>, a map that measures its container, a skeleton — still gets the full box, and an <img> or <video> is cropped to cover it rather than letterboxed. Content that must not be cropped should set object-contain on itself.
Reach for this when the height must be known before the content loads: a media grid that would otherwise reflow every time an image arrives is the usual case, and that reflow is the layout shift a Core Web Vitals score is measuring.
Anatomy
| Element | Description |
|---|---|
| Boxrequired | A relative, full-width <div> carrying aspect-ratio as an inline style. A style and not a class because Tailwind can only generate what it reads verbatim in the source, and this value arrives at runtime. |
| Childrenrequired | Every DIRECT child, taken out of flow and stretched to fill the box. That is what guarantees the ratio holds: nothing inside can contribute a height, so content with no intrinsic size of its own still gets the whole box. |
| Crop | object-cover on a direct <img> or <video>, so media fills the box rather than being letterboxed inside it. Content that must not be cropped sets object-contain on itself. |
Best practices
Do
- Reach for it wherever a reflow would otherwise happen when an image lands. That reflow is the layout shift a Core Web Vitals score measures, and reserving the box is the whole fix.
- Set object-contain on the child when the whole picture matters — a logo, a diagram, a screenshot. The default crops, which is right for a photograph and wrong for anything with an edge that means something.
- Give it a width. It is w-full, so inside a container with no width of its own it has no height either, and a box with a ratio and no size is a box that is not there.
Don’t
- Do not fall back to the padding-top percentage trick beside it. That percentage resolves against the WIDTH, which is why it works at all and also why it breaks as a flex child and eats the element’s own padding.
- Do not put text in it and expect the box to grow. Every child is absolutely positioned, so a paragraph longer than the box is clipped by overflow-hidden rather than pushing it open.
Examples
reserved boxes
Three boxes that know their height before anything is inside them. Each child here has no intrinsic size at all — it is an empty div — and the box holds open anyway, because every direct child is taken out of flow and stretched to fill it. That is the whole mechanism: nothing inside can contribute a height, so nothing inside can break the ratio.
a grid that cannot reflow
The case this exists for: a media grid whose covers have not arrived. Each box is already the right height, so when the images land nothing under them moves — and that movement is exactly what a Cumulative Layout Shift score is measuring. The skeleton has no size of its own; it fills the box because every direct child is stretched to it, which means the loading state and the loaded state occupy the same rectangle by construction rather than by two numbers someone kept in step.
the ratio wins
What the box does when the content does not fit, which is the trade nobody reads about until it bites. Every direct child is taken out of flow and the wrapper hides its overflow, so content longer than the box is CLIPPED rather than allowed to push the height — the ratio was the promise, and it is the promise kept. Where the words have to be readable, give the child its own scroll, as the second box does; where they do not, reach for a box that can grow instead of one that cannot.
Adds the five diagram renderers, the canvas chrome around them, and a share-card export at 1200 by 630. The specification types mirror archify, so a document authored for that tool renders here with no translation step.
Adds the five diagram renderers, the canvas chrome around them, and a share-card export at 1200 by 630. The specification types mirror archify, so a document authored for that tool renders here with no translation step.
Accessibility
- A plain box with no role: it constrains geometry and says nothing, so an <img> inside keeps its own alt and nothing is added to the accessible tree.
- Reserving the height before the content arrives is what stops the content under it moving out from under a pointer or a reader mid-tap.