Scrub Number Field
A compact field you scrub: press its handle and move sideways, or type, or use the arrow keys.
import { ScrubNumberField } from '@youj/react'
Installation & usage
npm i @youj/reactFor an app already set up with npx @youj/cli init, which installs the peers (@youj/core, @youj/motion, motion and Base UI) and wires the provider. New app? Start at Installation.
Use a scrub number field where people tune a number by feel and want the exact value too: a position, a blur, a rotation, an opacity. For a quantity entered in a form, with steppers and locale formatting, use a Number Input; for a value on a visible range, a Slider.
import { useState } from 'react'
import { ScrubNumberField } from '@youj/react'
export function Blur() {
const [blur, setBlur] = useState(24)
return <ScrubNumberField aria-label="Blur" label="B" unit="px" min={0} max={100} value={blur} onValueChange={setBlur} />
}The value is a number. Typed text commits on Enter or blur and is clamped but not snapped to the step, so 12.5 stays 12.5; text that isn't a number is put back. Both . and , are read as a decimal separator.
Description
A blur radius, scrubbed with the mouse and shown on the bar below.
Press the B and move left or right: the value changes one step for every few pixels, and keeps following the pointer when it leaves the field. Hold Shift to go ten times coarser and Alt ten times finer, and change your mind mid-drag: the pace follows the key as it is now. The value stops at min and max. A click on the handle, without moving, just focuses the field.
Pairs of small fields, with a letter, a symbol, a unit and a 0 to 1 range.
The label is the drag handle: a letter, a symbol or an icon. size="sm" fits a dense panel such as an Inspector Panel. step={0.1} makes Alt drag in hundredths.
Code
scrub-number-field-demo.tsx, the Demo story. The component itself comes from the package.
Reference
Propsvalue, defaultValue, onValueChange, min, max, step, label, unit…
Props
| Prop | Type | |
|---|---|---|
value | number | – |
defaultValue | numberdefault 0 | 0 |
onValueChange | (value: number) => void | – |
min | number | – |
max | number | – |
step | numberPer ArrowUp/Down and per few pixels of drag. default 1 | 1 |
largeStep | numberPer PageUp/PageDown. default step * 10 | step * 10 |
label | ReactNodeThe drag handle: an icon, or a letter. Hidden from assistive tech; name the field with | – |
unit | stringA plain suffix inside the field: "px", "%", "°". | – |
size | 'sm' | 'default'
default 'default' | 'default' |
locale | stringDefault: the YoujProvider locale. | – |
disabled | boolean | – |
readOnly | boolean | – |
invalid | boolean | – |
required | boolean | – |
name | string | – |
id | string | – |
ref | Ref<HTMLInputElement> | – |
onBlur | () => void | – |
className | string | – |
aria-label | stringNames the field for assistive tech ("Blur"). | – |
aria-labelledby | string | – |
Data attributes
The root carries data-slot="scrub-number-field" and data-size (sm or default), plus data-yj-scrubbing while the handle is being dragged. The handle is scrub-number-field-handle in data-slot.
AccessibilitySpinbutton, keys, value text
Accessibility
- The field is an input with
role="spinbutton"andaria-valuenow,aria-valuemin,aria-valuemaxand anaria-valuetextthat reads the value with its unit ("24 px"). Name it witharia-labeloraria-labelledby; the handle is hidden from assistive technology. - ArrowUp and ArrowDown step by
step, with Shift ×10 and Alt ×0.1. PageUp and PageDown step bylargeStep(default ten steps). Home and End go tominandmax. - Dragging is an extra for pointer users: everything it does is available from the keyboard.
- The mouse wheel never changes the value, so a scrolling page doesn't edit a form.
- Nothing animates, so there is no reduced motion to honor; a drag changes the value directly.