Settings row for a ratio: the row prints it and draws it, and opens an editor with the ratios worth a name plus both sides always editable. It is kept as two numbers rather than as their quotient, since 16:9 is what a reader recognises.
The import and the props worth knowing about, in one place.
import { InspectorAspect } from "@/components/beste/component/inspector-aspect";
// Uncontrolled
<InspectorAspect label="Aspect Ratio" defaultValue={{ w: 16, h: 9 }} />
// Controlled, with a separate commit for expensive work
<InspectorAspect
label="Aspect Ratio"
value={ratio}
onValueChange={setRatio}
onValueCommit={(value) => save(value)}
/>
<InspectorAspect
label="Thumbnail"
icon={RatioIcon} // optional leading icon
tone="outline" // "muted" (default) | "outline" | "ghost"
size="sm" // "sm" | "default" | "lg"
maxSide={64} // largest either side may be
presets={[ // shortcuts, not the set of allowed answers
{ w: 1, h: 1, label: "Square" },
{ w: 4, h: 5, label: "Feed" },
]}
value={ratio}
onValueChange={setRatio}
/>
// What the value turns into
<div style={{ aspectRatio: `${ratio.w} / ${ratio.h}` }} />
// Sides are reduced by their common factor for display, so a value of 1920 by 1080
// still reads as 16:9. A ratio nobody named is still a ratio, so the menu
// simply sits on "Custom".Read from the component's own type, so this cannot drift from what it accepts.
| Prop | Type | Default | Description |
|---|---|---|---|
label* | string | — | Label rendered on the left, inside the row. |
icon | LucideIcon | — | Optional leading icon shown before the label. |
value | AspectValue | — | Controlled value. Pair it with `onValueChange`. |
defaultValue | AspectValue | — | Initial value in uncontrolled mode. |
onValueChange | (value: AspectValue) => void | — | Fires on every adjustment. |
onValueCommit | (value: AspectValue) => void | — | Fires once an adjustment is finished — a preset chosen, a side committed. Use it for work too expensive to run per keystroke. |
onOpenChange | (open: boolean) => void | — | Fires when the editor opens or closes. |
presets | AspectPreset[] | the six ratios anyone can name | Which ratios to offer by name. The two sides stay editable regardless, so this is a set of shortcuts rather than a set of allowed answers. |
maxSide | number | 100 | Largest either side may be. |
disabled | boolean | — | Block interaction and dim the row. |
tone | "muted" | "outline" | "ghost" | "muted" | Surface treatment: filled (default), hairline outline, or bare until hover. |
size | "sm" | "default" | "lg" | "default" | Row height preset. |
className | string | — | |
aria-label | string | — | Accessible name. Falls back to `label`. |