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.
Adds the component and everything it depends on to your project.
npx shadcn add https://ui.beste.co/component/r-base/inspector-positionNew here? Read the installation guide.
The import and the props worth knowing about, in one place.
import { InspectorPosition } from "@/components/beste/component/inspector-position";
// Uncontrolled. The value is two percentages from the top left corner.
<InspectorPosition label="Focal Point" defaultValue={{ x: 50, y: 30 }} />
// Controlled, with a separate commit for expensive work
<InspectorPosition
label="Focal Point"
value={point}
onValueChange={setPoint}
onValueCommit={(value) => save(value)}
/>
// Pass the picture and the pad stops being a diagram of the surface
<InspectorPosition
label="Focal Point"
preview={`url(${image})`}
value={point}
onValueChange={setPoint}
/>
<InspectorPosition
label="Origin"
icon={CrosshairIcon} // optional leading icon
tone="outline" // "muted" (default) | "outline" | "ghost"
size="sm" // "sm" | "default" | "lg"
snap={false} // stop pulling towards the thirds
step={5} // percent a key press moves; Shift moves ten of them
name="origin" // submits as origin-x and origin-y
value={point}
onValueChange={setPoint}
/>
// What the value turns into
<div style={{ objectPosition: `${point.x}% ${point.y}%` }} />
<div style={{ backgroundPosition: `${point.x}% ${point.y}%` }} />
<div style={{ transformOrigin: `${point.x}% ${point.y}%` }} />
// A radial gradient's centre, which is the one thing inspector-gradient cannot say
const background = `radial-gradient(circle at ${point.x}% ${point.y}%, #6366f1, #0ea5e9)`;Turn the props on the right; the snippet under them is what you would write to get what you see.
import { InspectorPosition } from "@/components/beste/component/inspector-position";
<InspectorPosition
label="Focal Point"
className="w-72"
defaultValue={{"x":50,"y":30}}
/>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 keys | One step on the focused axis. |
|---|---|
| Shift + Arrow | Ten steps. |
| Home / End | Send the axis to 0% or 100%. |
| Page Up | Centre the axis at 50%. |
| Drag on the pad | Moves the point; `snap` pulls it towards the thirds and the centre. |
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 | PositionValue | — | Controlled value. Pair it with `onValueChange`. |
defaultValue | PositionValue | — | Initial value in uncontrolled mode. Defaults to the centre. |
onValueChange | (value: PositionValue) => void | — | Fires on every frame of a drag, and on every key press. |
onValueCommit | (value: PositionValue) => void | — | Fires once a change is finished — the pad released, a key released, a named spot pressed. Use it for work too expensive to run per frame. |
onOpenChange | (open: boolean) => void | — | Fires when the editor opens or closes. |
snap | boolean | true | Pull the point onto the thirds when it comes within a few percent of them. Hold Shift while dragging to place it exactly instead. |
step | number | 1 | Smallest increment a key press moves, in percent. |
preview | string | — | What the pad shows behind the point. Any CSS image: pass the picture being positioned and the pad becomes the thing itself rather than a diagram of it. |
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 underlying range inputs, so the row can take part in a form. The two axes submit as `{name}-x` and `{name}-y`. |
className | string | — | |
aria-label | string | — | Accessible name. Falls back to `label`. |
Settings row for a direction: a dial you drag round, reading in degrees the way CSS does (zero up, growing clockwise), with a range input underneath carrying the keyboard and the form.
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.
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.
Settings row whose choices sit side by side on the right, with a marker that slides between them: the readable alternative to a switch when the two states deserve names, and the compact one to a select at three or four options.