// preview in
saved for every page

AspectRatio

Keeps a box at a fixed proportion, like 16:9 or 1:1, at any width. Use it for videos, embeds, maps and thumbnails, so the space is reserved before the media loads and every card in a row lines up.

Pattern CSS aspect-ratio + object-fitServer componentSource ↗

Installation

Set up Camaleo once (Installation), then import it. It has no state, so it renders on the server.

import { AspectRatio } from "@camaleo/react";

Anatomy

One box with position: relative and hidden overflow. A direct img, video or iframe fills it; anything else you lay on top with position: absolute.

Examples

Every example is a real file you can copy. They all wear the skin, mode and brand from the bar above.

minimal · light · #3fa34d
12:48
How to roast coffee at home

Module 2 · Lesson 4

Green hills at sunset with a pale sun
ratio={16 / 9}

Pick a ratio

Switch the ratio. ratio is width divided by height, so write it as a fraction: 16 / 9 for video, 4 / 3 for photos, 1 for squares, 3 / 4 for portraits.

Stoneware mug with a wide handle
cover: fills the box, crops the edges
Stoneware mug with a wide handle
contain: shows it all, leaves bands

cover or contain

cover, the default, fills the box and crops what doesn't fit. Set objectFit: "contain" on the image when every edge matters, like a product or a logo.

Green hills at sunset with a pale sun

Pousada da Serra

Monte Verde, MG

$76 / night
A sailing boat on a calm blue sea

Casa do Farol

Ilhabela, SP

$118 / night
A lighthouse on a rocky cape at dusk

Chalé Vista Mar

Ubatuba, SP

$94 / night

Cards with photos of any shape

The three photos are 16:9, 4:3 and 3:4. Cut to the same ratio, the cards are the same height and the titles line up.

  • Hills at sunset, Monte Verde
  • Sailing off Ilhabela
  • The lighthouse at Ponta das Canas
  • Morning fog over the hills
  • Boats in the harbour
  • The cape at dusk

Thumbnail grid

Square thumbnails make a tidy grid whatever was uploaded. object-position chooses which part of the photo survives the crop.

Rua Augusta 1200, São Paulo

Embeds need a title

An iframe fills the box like an image does. Give it a title that says what's inside: it is the frame's name for screen readers.

A sailing boat on a calm blue sea

Casa do Farol, Ilhabela. This line stays put while the photo loads.

Space kept while loading

Reload the photo. The box has its height before the file arrives, so the text below never jumps, and a status message says when it's ready.

In context

Media rarely stands alone. These are whole pieces of UI you can copy, in the skin you picked.

12:48

Home Barista course · Module 2 · Lesson 4

How to roast coffee at home

Course progress9 of 15 lessons
x
Course lessonAspectRatio · IconButton · Progress · Button
Living room with a green sofa and a large windowNew

2-bedroom apartment in Pinheiros

68 m² · 2 bedrooms · 1 parking space

$540/month
Rental listingCard · AspectRatio · Badge · Button
Map of the Consolação area with a pin on Rua Augusta, two blocks from Paulista Avenue

Grão Coffee Co. · Augusta

Address
Rua Augusta 1200, São Paulo
Hours
Mon–Sat, 7 AM to 7 PM
Phone
+55 11 3256-4821
Get directions
Store locationCard · AspectRatio · DataList · Link

Guidelines

Green hills at sunset with a pale sun
Pousada da Serra
A sailing boat on a calm blue sea
Casa do Farol
A lighthouse on a rocky cape at dusk
Chalé Vista Mar
DoOne ratio per row.

Photos of any shape end up the same size, and the titles line up.

Green hills at sunset with a pale sunPousada da Serra
A sailing boat on a calm blue seaCasa do Farol
A lighthouse on a rocky cape at duskChalé Vista Mar
Don’tEvery photo in its own shape.

The row goes ragged and the eye follows the gaps instead of the content.

Grão Coffee Co.
Docontain for logos and products.

Their edges carry meaning; show all of it, with some padding.

Grão Coffee Co.
Don’tcover on a wide logo.

The crop cuts off the brand name, which is the whole point.

Props

PropTypeDefaultDescription
rationumber1Width divided by height: 16 / 9 for video, 4 / 3 for photos, 1 for a square.

Every attribute of a <div> passes through, like style and className. Set a width (or let the parent's grid set it); the height always follows the ratio.

Styling hooks

Restyle it without forking: target the slot, or set the custom property in your own CSS.

Attributes

data-slot"aspect-ratio"
--cml-aspect-ratiothe ratio, as a number

Tokens it reads

This component only

--cml-aspect-ratio
/* wider video on large screens, taller on phones */
.lesson [data-slot="aspect-ratio"] {
  --cml-aspect-ratio: 4 / 3;
}
@media (min-width: 48rem) {
  .lesson [data-slot="aspect-ratio"] {
    --cml-aspect-ratio: 16 / 9;
  }
}

Accessibility

—The box isn't interactive and takes no focus. Tab reaches the controls you put inside it, like a play button.
Was this page helpful? · Edit this page on GitHub