Settings row for the four edges of a box: the row carries a CSS-shorthand summary, and opens a cross where each field sits on the edge it sets, tied together or not.
Adds the component and everything it depends on to your project.
npx shadcn add https://ui.beste.co/component/r-base/inspector-spacingNew here? Read the installation guide.
The import and the props worth knowing about, in one place.
import { InspectorSpacing } from "@/components/beste/component/inspector-spacing";
// Uncontrolled. The row reads "16 24 px"; the cross opens on click, and the link
// toggle in its middle starts on when all four edges already match.
<InspectorSpacing label="Padding" defaultValue={{ top: 16, right: 24, bottom: 16, left: 24 }} suffix="px" />
// Controlled, with a separate commit for expensive work
<InspectorSpacing
label="Margin"
value={margin}
onValueChange={setMargin} // every accepted keystroke
onValueCommit={(value) => console.log("persist", value)} // Enter or blur
min={0}
max={128}
step={4}
suffix="px"
/>
<InspectorSpacing
label="Inset"
icon={Frame} // optional leading icon
linked={linked} // take the link state over, if it belongs to your state
onLinkedChange={setLinked}
onOpenChange={(open) => console.log("editor open:", open)}
value={inset}
onValueChange={setInset}
tone="outline" // "muted" (default) | "outline" | "ghost"
size="sm" // "sm" | "default" | "lg"
/>
// Always four edges, no tie-together toggle
<InspectorSpacing label="Border width" hideLink max={12} value={border} onValueChange={setBorder} />Turn the props on the right; the snippet under them is what you would write to get what you see.
import { InspectorSpacing } from "@/components/beste/component/inspector-spacing";
<InspectorSpacing
label="Padding"
className="w-72"
defaultValue={{"top":16,"right":24,"bottom":16,"left":24}}
suffix="px"
/>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 focused edge. |
|---|---|
| Shift + Arrow | Ten steps. |
| Enter | Accept what was typed into the field. |
| Escape | Throw the draft away and put the committed value back. |
| The link toggle | Ties the four edges together; typing into one then writes all four. |
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 | Partial<Record<EdgeKey, number>> | — | Controlled value. Pair it with `onValueChange`. |
defaultValue | Partial<Record<EdgeKey, number>> | — | Initial value in uncontrolled mode. |
onValueChange | (value: SpacingValue) => void | — | Fires on every accepted keystroke and every step. |
onValueCommit | (value: SpacingValue) => void | — | Fires once an edit is finished — Enter, or leaving a field. |
onOpenChange | (open: boolean) => void | — | Fires when the editor opens or closes. |
min | number | 0 | Smallest value an edge may hold. |
max | number | 999 | Largest value an edge may hold. |
step | number | 1 | Amount one arrow key press moves an edge. |
suffix | string | — | Muted unit after the summary, e.g. "px", "rem". |
defaultLinked | boolean | — | Start with the edges tied together. Defaults to on when the incoming value already has four equal edges, which is the usual starting point. |
linked | boolean | — | Controlled link state, if the toggle belongs to your own state. |
onLinkedChange | (linked: boolean) => void | — | |
hideLink | boolean | — | Drop the link toggle and always edit the four edges separately. |
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 for the group. Falls back to `label`. |
Settings row for the four corners of a box: the row carries a border-radius shorthand summary and a glyph rounded to match, and opens a square where each field sits on the corner it rounds.
Settings row for a point on a surface: the row names the nine spots CSS names and shows the rest as two percentages, and opens a square pad the point is dragged around, with the thirds drawn on it and a pull towards them.
Settings row for a border: the row draws one exactly as described beside a summary of it, and opens an editor with the sides as icon toggles and the width, style and colour under them, each one a row of the family.
The columns of a grid as a list of lengths: the row shows the CSS it comes to, the editor holds one length per line with a picture of the shares above them. There is no reordering on purpose, because a track's place in the list is its place in the grid.
Settings row for a CSS filter stack, all ten functions of it: the row shows the whole stack applied to something, and opens an editor holding the nine numeric filters as rows of the family plus a drop shadow section, over a preview large enough to judge.
Where the contents of a box sit in it: nine cells drawn in visual terms, mapped onto justify and align afterwards so the pair swapping places under a column direction is the component's problem and not the reader's. Direction, distribution and stretch sit under the pad as rows of the family, since each is a setting like any other.