Xzero UI
Pro library

Scrub input

A Figma-style number field: drag the label to scrub, or type values, units, and arithmetic.

$ pnpm dlx shadcn@4.23.0 add @xzero-ui/scrub-input
Live · keyboard ready

When to use

When not to use

Installation

Register both Xzero UI namespaces in your project's components.json:

{
  "registries": {
    "@xzero-ui": "https://mcp.xzero.co.uk/r/{name}.json",
    "@xzero-ui-pro": "https://mcp.xzero.co.uk/r/pro/{name}.json"
  }
}
npx shadcn@4.23.0 add @xzero-ui/scrub-input

Install xzero-foundation once, and import @/components/xzero/foundation.css in your app root. No Xzero token is used by this snapshot. For sample portraits, photos, fonts, or logos, download https://mcp.xzero.co.uk/install-assets.mjs and run node xzero-install-assets.mjs <receiving-project>.

Usage

import { useState } from "react";
import { ScrubInput } from "@/components/xzero/scrub-input/scrub-input";

export function LayerInspector() {
  const [width, setWidth] = useState(240);
  const [opacity, setOpacity] = useState(100);
  return (
    <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8 }}>
      <ScrubInput label="W" value={width} onValueChange={setWidth} min={0} units={["px", "%"]} resetValue={240} />
      <ScrubInput label="Opacity" value={opacity} onValueChange={setOpacity} min={0} max={100} unit="%" />
    </div>
  );
}

Examples

Rotation that wraps

<ScrubInput label="R" min={0} max={360} wrap unit="°" units={["°"]} fineStep={0.1} onValueCommit={value => setRotation(value)} />

API reference

ScrubInput

A compact number field for inspectors: drag the label to scrub, or type values with arithmetic and units, with rubber-band limits.

PropTypeDefaultDescription
label (required)ReactNode–Text or a 16px icon. It is the scrub handle. Icon labels need aria-label.
valuenumber–Controlled value.
defaultValuenumber0Starting value when uncontrolled.
onValueChange(value: number, details: ScrubInputChangeDetails) => void–Fires for every change, including each scrub step. details is { source: "scrub" | "type" | "key" | "reset", unit }.
onValueCommit(value: number, details: ScrubInputChangeDetails) => void–Fires once when a change settles: a scrub ends, Enter or blur commits typing, or a key step lands.
minnumber-InfinityLower limit.
maxnumberInfinityUpper limit.
stepnumber1One step for arrows and scrubbing.
fineStepnumberstep / 10Step with Alt held.
coarseStepnumberstep * 10Step with Shift held. Coarse steps snap to the coarse grid.
precisionnumber–Decimal places kept. Defaults to the precision of step or fineStep.
pixelsPerStepnumber2Pointer travel in px for one step while scrubbing.
wrapbooleanfalseWraps from max to min, as rotation does. Needs both limits.
unitstring–Controlled unit shown after the number. With more than one entry in units it becomes a button that cycles them.
defaultUnitstring–Starting unit when uncontrolled. Defaults to unit or the first of units.
unitsreadonly string[]–Units a typed value may carry, such as ["px", "%"]. Defaults to the current unit.
onUnitChange(unit: string) => void–Called when a typed unit or the unit button changes the unit.
resetValuenumber–Double click the label to return here.
trackbooleantrue when min and max are setShows where the value sits between min and max as a quiet fill.
size"sm" | "md""md"Field height: 30px, or the small control height.
pointerLockbooleantrueLocks the mouse pointer while scrubbing when the browser allows it.
classNamestring–Class on the root.
...propsInputHTMLAttributes<HTMLInputElement>–Forwarded to the input, except value, defaultValue, onChange, type, size, min, max, step, and prefix.
refRef<HTMLInputElement>–The input element.

evaluateScrubExpression

Evaluates + - * / and parentheses over numbers that may carry a unit. Returns { value, unit? }, or null for anything else or an unknown unit.

PropTypeDefaultDescription
text (required)string–The typed expression, such as "(100-24)/2" or "50%". Commas read as decimal points.
units (required)readonly string[]–Allowed units. deg and ° are aliases.

Keyboard interactions

KeysAction
ArrowUp / ArrowDownSteps the value; Shift steps ten times coarser, Alt ten times finer.
EnterCommits typed text, including arithmetic such as 12*2.
EscapeRestores the last value while typing, or cancels a scrub back to where it started.
Shift / Alt (while scrubbing)Switches to coarse or fine steps mid-drag and shows the multiplier.

Accessibility

Motion

Responsive behavior

Performance

Notes for AI

Also in special inputs

Guidance for AI tools

Scrub input: A Figma-style number field: drag the label to scrub, or type values, units, and arithmetic. Follow the declared prop types and do not invent props. Keep keyboard access, reduced motion support, and both light and dark themes intact when adapting it.

Full library index: https://ui.xzero.co.uk/llms.txt

Browse all components