A number and the unit that gives it meaning, in one row: px, rem, a percentage, or a keyword like auto that is the whole value on its own. Each unit may bring its own range, so a percentage stops at 100 while pixels do not.
Adds the component and everything it depends on to your project.
npx shadcn add https://ui.beste.co/component/r-base/inspector-unitNew here? Read the installation guide.
The import and the props worth knowing about, in one place.
import { InspectorUnit } from "@/components/beste/component/inspector-unit";
// Uncontrolled
<InspectorUnit label="Width" defaultValue={{ value: 100, unit: "%" }} />
// Controlled, with a separate commit for expensive work
<InspectorUnit
label="Max width"
value={width}
onValueChange={setWidth}
onValueCommit={(value) => save(value)}
/>
// A unit that is the whole value: the number field steps aside rather than sitting
// there holding a figure that means nothing
<InspectorUnit
label="Height"
units={["px", "%", "vh", { value: "auto", valueless: true }]}
value={height}
onValueChange={setHeight}
/>
// A range per unit, since 0 to 100 reads as a percentage and 0 to 9999 does not
<InspectorUnit
label="Offset"
units={[
{ value: "px", min: -400, max: 400 },
{ value: "%", min: -100, max: 100 },
{ value: "rem", min: -24, max: 24, step: 0.25 },
]}
value={offset}
onValueChange={setOffset}
/>
<InspectorUnit
label="Letter spacing"
icon={TypeIcon} // optional leading icon
tone="outline" // "muted" (default) | "outline" | "ghost"
size="sm" // "sm" | "default" | "lg"
units={["em", "px"]}
step={0.01}
precision={3} // decimals kept on commit
name="tracking" // submits as tracking and tracking-unit
value={tracking}
onValueChange={setTracking}
/>
// What the value turns into
const css = value.unit === "auto" ? "auto" : `${value.value}${value.unit}`;
// The arrows work the field the way they work a stepper, and Shift moves ten steps.Turn the props on the right; the snippet under them is what you would write to get what you see.
import { InspectorUnit } from "@/components/beste/component/inspector-unit";
<InspectorUnit
label="Width"
className="w-72"
defaultValue={{"value":100,"unit":"%"}}
units={["px","%","rem",{"value":"auto","label":"auto","valueless":true}]}
/>Every one of these is in the component already. They are listed because a props table cannot mention a gesture, so nothing else on this page can tell you they exist.
| Arrow Up / Down | One step on the number, the way a stepper moves: a length is a number first and a string second. |
|---|---|
| Shift + Arrow | Ten steps. |
| Enter | Accept what was typed. |
| Escape | Throw the draft away and put the committed value back. |
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 | UnitValue | — | Controlled value. Pair it with `onValueChange`. |
defaultValue | UnitValue | — | Initial value in uncontrolled mode. |
onValueChange | (value: UnitValue) => void | — | Fires on every accepted edit and on every unit change. |
onValueCommit | (value: UnitValue) => void | — | Fires once an edit is finished — the field left or Enter pressed, a unit chosen. Use it for work too expensive to run per keystroke. |
units | (string | InspectorUnitOption)[] | ["px", "%", "rem"] | The units on offer. Plain strings are enough when the unit is its own label. |
min | number | 0 to 9999, in steps of 1 | Range the number answers to, for units that do not name their own. |
max | number | — | |
step | number | — | |
precision | number | 2 | How many decimals a value keeps. Anything typed past this is rounded on commit, so what the field shows is what the caller was handed. |
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. |
name | string | — | Name of the number field, so the row can take part in a form. |
id | string | — | Id of the number field, for an external `<label htmlFor>`. |
className | string | — | |
aria-label | string | — | Accessible name. Falls back to `label`. |
The row that reports rather than asks: a measurement the work produced, shown in the family's surface so it can sit among the settings that caused it. Threshold bands colour the bar and the number without the caller recomputing them, and it is a meter rather than a progress bar, which is how it is announced.
The line of prose that belongs between rows: what a setting is for, why one is switched off, what a value will cost. Four tones, each with its own mark, and the same text size as the rows around it.
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 container the rows go in: a named, collapsible section that says what it is currently set to while it is closed, with an optional reset in its header. A drawer of twenty settings becomes a drawer of five groups.