Aspect ratio
A frame kept to a ratio and marked the way a printer marks a crop: short lines outside each corner, never a border.
Report an issue with Aspect ratioExample
16 by 9
16 by 9
16 by 9
crop, 16 : 9
16 by 9
crop, 4 : 5
4 by 5
diagonal, 16 : 9
16 by 9
diagonal, 4 : 5
4 by 5
square, 16 : 9
16 by 9
square, 4 : 5
4 by 5
Install
Run it in a project that has the shadcn CLI set up. It brings the 0nlyType base along.
npx shadcn@latest add https:// thedirectors.agency/ ui/ r/aspect-ratio.jsonUsage
This example also uses Toggle group.
npx shadcn@latest add https:// thedirectors.agency/ ui/ r/ toggle-group.json"use client"import * as React from "react"import { AspectRatio } from "@/components/ui/aspect-ratio"import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"const ratios = [["16:9", 16 / 9],["4:3", 4 / 3],["1:1", 1],["4:5", 4 / 5],] as constexport default function Example() {const [ratio, setRatio] = React.useState("16:9")const value = ratios.find(([name]) => name === ratio)?.[1] ?? 16 / 9return (<div className="grid gap-10">{/* Radix single groups clear on a second press; a ratio is always one of the four. */}<ToggleGroup type="single" value={ratio} onValueChange={(v) => v && setRatio(v)} aria-label="Ratio">{ratios.map(([name]) => (<ToggleGroupItem key={name} value={name}>{name}</ToggleGroupItem>))}</ToggleGroup>{/* One ratio, three frames: the crop, the diagonal and the square all follow the choice. */}<div className="grid items-start gap-x-16 gap-y-14 sm:grid-cols-3"><AspectRatio ratio={value} label /><AspectRatio ratio={value} label variant="diagonal" /><AspectRatio ratio={value} label variant="square" /></div></div>)}Contract
- Underneath: native
aspect-ratio. - Anatomy:
<div class="ot-ratio" data-variant="crop | diagonal | square" data-orient="landscape | portrait | square" style="--ratio: 1.7778">, with aot-fractionnaming it (aria-hidden; a.ot-srsays "16 by 9"), and for the square.ot-ratio-restholding the remainder's fraction.--ratiois a registered number, so it eases; registered, it doesn't inherit, so--rcarries it to the parts and pseudo-elements. The fraction keeps to the frame (min(--ot-f, 17cqi)). - A frame kept to a ratio and marked like a printer's crop: short lines outside each corner and nothing between them, no border. Change
--ratioand the frame eases to it while the fraction rolls. - Diagonal: the paste-up artist's scaling line, a hairline from the foot of the start edge to the head of the end edge. Any frame whose corner lies on it has the same ratio, which is how a picture was scaled before software. The ratio is written along the line, standing on it (
rotate(-atan2(1, --r))), so as the frame eases the line and the words swing together. Mirrored in right-to-left. - Square: the largest square is ruled off from the start edge, or from the head when the frame stands tall, the way a book designer finds the square in a page and the rectangle it leaves. The ratio sits in the square; what's left is named by its own ratio in the pencil (16 : 9 leaves 7 : 9, 4 : 5 leaves 4 : 1). The rule is a background placed at
100% / --r, so it glides as the frame eases, and its length is clamped to nothing at 1 : 1, where there is nothing left. The remainder's name fades back in once the rule has arrived. - Forced colours keep the marks and lines (they are background images) in CanvasText.
Props
| Prop | Type | Default | What it does |
|---|---|---|---|
variant | "crop" | "diagonal" | "square" | "crop" | crop: only the printer's trim marks outside the corners. diagonal: the paste-up artist's scaling line, from the foot of the start edge to the head of the end edge, with the ratio written along it, standing on it; every frame whose corner lies on that line has the same ratio, and as the ratio changes the line and the words swing together. square: the largest square is ruled off from the start, or from the head when the frame stands tall, and what's left is named by its own ratio in the pencil (16 : 9 leaves 7 : 9); the rule glides as the ratio eases, and at 1 : 1 there is nothing left. |
ratio | number | 16 / 9 | Width over height. Change it and the frame eases to the new ratio. |
label | true | ReactNode | true sets the ratio in the middle as a fraction, which rolls when the ratio changes. Any other node is shown as given. |
Craft
Where its move comes from
| Component | Reference | Move |
|---|---|---|
| Resizable, aspect ratio | Paul Rand dimension lines | Shares measured; a printer's crop marks |
| Diagonal aspect ratio | The paste-up artist's scaling diagonal | The ratio written along the line that keeps it |
| Square aspect ratio | The book designer's square in the page | The square ruled off, the rest named by its own ratio |
How it moves
| Component | Articulation | What moves |
|---|---|---|
| Aspect ratio | Breath | The frame eases to the ratio; the fraction rolls |
| Diagonal aspect ratio | Swing | The line and the ratio written on it swing to the new diagonal with the frame |
| Square aspect ratio | Glide | The square's rule glides to its new place; the remainder's name comes back once it lands |