Inspector Scrub

A number with no ends, dragged from the row itself: for the values that have no maximum worth naming, like a z-index, an X offset or a letter-spacing. The drag is relative rather than positional, so pressing anywhere is safe, and a soft range gives the bar something to draw against that the value is free to leave. Only the reported number is quantized, so the pointer never fights the grid.

em

Installation

Adds the component and everything it depends on to your project.

npx shadcn add https://ui.beste.co/component/r-base/inspector-scrub

New here? Read the installation guide.

Usage

The import and the props worth knowing about, in one place.

import { InspectorScrub } from "@/components/beste/component/inspector-scrub";

// Both bounds optional, which is the point: neither of these has an honest maximum
<InspectorScrub label="Letter spacing" defaultValue={0} step={0.01} suffix="em" sensitivity={8} />

// The bar, for a number that has no ends. `softMin`/`softMax` are the span worth
// working in, not a limit: the fill shows where the value sits in that span, pins
// once it is past it, and the number carries on. With no span there is no bar,
// since a bar over an unknown range would have to invent one.
<InspectorScrub label="Letter spacing" softMin={-0.1} softMax={0.4} step={0.01} suffix="em" />

<InspectorScrub
  label="X offset"
  value={x}
  onValueChange={setX}                       // every step of the drag
  onValueCommit={(next) => console.log("settled on", next)}  // when the drag ends
  step={1}
  precision={0}
  sensitivity={4}      // pixels of drag per step; lower is faster
  suffix="px"
  name="x-offset"
  tone="outline"       // "muted" (default) | "outline" | "ghost"
  size="sm"            // "sm" | "default" | "lg"
/>

// Bounded on one side only, which no slider can express
<InspectorScrub label="Z index" min={0} step={1} precision={0} />

Playground

Turn the props on the right; the snippet under them is what you would write to get what you see.

em
Usage
import { InspectorScrub } from "@/components/beste/component/inspector-scrub";

<InspectorScrub
  label="Letter spacing"
  className="w-72"
  defaultValue={0}
  step={0.01}
  suffix="em"
  sensitivity={8}
  softMin={-0.1}
  softMax={0.4}
/>

Keyboard and gestures

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.

Hover the rowLights the whole track and shows the grip
Drag the rowRuns the number with the pointer, from wherever you pressed
Shift + dragTen times the step
Alt + dragA tenth of it
Click the labelPuts the caret in the field to type an exact value
Up / DownStep the value; Shift for ten of them
EscapeThrow away what was typed

Props

Read from the component's own type, so this cannot drift from what it accepts.

PropTypeDefaultDescription
label*stringLabel rendered on the left, inside the row.
iconLucideIconOptional leading icon shown before the label.
valuenumberControlled value. Pair it with `onValueChange`.
defaultValuenumberInitial value in uncontrolled mode.
onValueChange(value: number) => voidFires on every change, including each step of a drag.
onValueCommit(value: number) => voidFires when a drag ends or an edit is committed.
minnumberHard bounds, both optional, which is the point of this row. A z-index, an X offset or a letter-spacing has no honest maximum, and a slider that invents one is a slider whose whole range is a lie. What is given here the value is held to.
maxnumber
softMinnumberThe range the **bar** is drawn against, which the value is free to leave. It is how an endless number gets a picture: the fill shows where the value sits in the span you would usually be working in, pins at the end once it is past that, and the number keeps going. Give both or neither. Falls back to `min` and `max`, so a row with hard bounds already looks like a slider, and a row with none has no bar at all rather than a made-up one.
softMaxnumber
stepnumber1What one step of the drag is worth, and what the arrows move by.
precisionnumber2How many decimals the reported value keeps.
sensitivitynumber4Pixels of drag per step. Lower is faster; the default asks for four pixels a step, which is quick enough to cross a range and slow enough to land on a number.
suffixstringPrinted after the number, e.g. `px`, `%`, `em`.
disabledbooleanBlock 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.
namestringName of the field, so the row can take part in a form.
idstringId of the field, for an external `<label htmlFor>`.
classNamestring
aria-labelstringAccessible name. Falls back to `label`.

More Inspector components

View all Inspector

Inspector Tabs

The strip that splits a settings panel into two or three questions instead of one long scroll. It is the strip and nothing else: what the tabs switch between stays in the panel's own markup, beside the state that decides it. The pill slides between equal columns, arrow keys both move and select, and a tab can carry a count of what has changed under it.

Inspector Action

The row that does something instead of holding something: open a sub-panel, replace an asset, regenerate a key, delete the section. It carries a description, a hint, a busy spinner and a destructive treatment, and renders as a plain anchor when given an href.

Inspector Range

Settings row for a span rather than a value: two thumbs on the row itself, the band between them filling it, and both ends of the pair read out on the right. Ticks, tones and thumb states follow inspector-slider exactly, appearing on hover.

Inspector Position

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.

Dark Mode

Inspector Segmented

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.

Inspector Spacing

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.