Components / Inputs

ScrubInput

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

Install

npx shadcn@latest add https://irisui.dev/r/scrub-input.json
import { ScrubInput } from "@/components/iris/scrub-input/scrub-input";
Registry item scrub-inputBrings in foundationRegistry JSON

Preview

ScrubInput

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

When to use

  • Inspector and properties panels: sizes, positions, rotation, opacity.
  • Numeric parameters people tune by feel (storage, spacing) where dragging beats typing.
  • Not for picking from a range with a visible handle; use Slider.
  • Not for money amounts; use MoneyInput.

Usage

import { ScrubInput } from "@/components/iris/scrub-input/scrub-input";

const [width, setWidth] = useState(240);
h(ScrubInput, { label: "W", value: width, onValueChange: setWidth, min: 0, units: ["px", "%"], resetValue: 240 });
h(ScrubInput, {
  label: "R",
  min: 0,
  max: 360,
  wrap: true,
  unit: "°",
  units: ["°"],
  fineStep: 0.1,
  onValueCommit: setRotation,
});

Props

Prop Type Default Description
label ReactNode required Text or a 16px icon; dragging it scrubs. Icon labels need aria-label.
value / defaultValue number – / 0 Controlled or initial value.
onValueChange (value, { source, unit }) => void – Every change, including each scrub step.
onValueCommit (value, details) => void – Once a change settles: scrub end, Enter/blur, or a key step.
min / max number -Infinity / Infinity Limits.
step / fineStep / coarseStep number 1 / step/10 (Alt) / step*10 (Shift) Step sizes.
precision number from fineStep Decimal places kept.
pixelsPerStep number 2 Pointer travel per scrub step.
wrap boolean false Wrap from max to min (needs both limits).
unit / defaultUnit / units / onUnitChange string / string[] – Unit after the number; several units make it a cycling button.
resetValue number – Double-click the label to return here.
track boolean on when min and max are set Quiet fill showing position within the range.
size "sm" | "md" "md" Field height.
pointerLock boolean true Lock the pointer while scrubbing where allowed.
className string – Root class; set --scrub-input-width there to size the field (it fills its column by default).
...input props InputHTMLAttributes – Forwarded to the input (disabled, name, ref).

Notes

  • Keyboard: ArrowUp/Down step (Shift coarse, Alt fine); Enter commits typed text including arithmetic; Escape restores while typing or returns to the start while scrubbing.
  • The input is a spinbutton with current, min and max values; percent and degree values are spelled out. Invalid text sets aria-invalid briefly and keeps the previous value.
  • Reduced motion removes the edge strain, shake and glide; unit changes fade.
  • Reads hover for the resting shell, surface and line-strong on focus, red for an invalid entry, and ink-3 for the label and unit.