KQ-1508 · DRAG/NUMBER

Drag Number

A numeric field you scrub by its label: a slow drag moves one step per few pixels, a fast one shifts up a gear to ×10 (×100 on long ranges) and snaps to that grid, while the digits roll on real odometer wheels that follow the value on springs.snap, carrying from 9 to 0 the way a counter does. A tick bar appears under the value as a tape beneath a fixed needle, moving 1:1 with the finger at every gear, zooming about the needle on springs.snap when the gear changes and rubber-banding past min and max before settling on springs.snap with the release velocity. It stays a real text input: type and Enter to commit, Escape to revert, ArrowUp and ArrowDown to step (Shift ×10, PageUp/PageDown ×10, Home and End to the ends), with the same tape gliding to each new value.

KQ-1508 · DRAG/NUMBER

Contours

Fieldline · Ridge survey

Drag the label sideways to scrub. Arrow keys step, Shift steps ten.

opacity 72% · drag the label or type

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/drag-number

Props

label
string
default —
The field's name: shown on the left, and the handle you scrub.
value / defaultValue
number
default — / 0
The value, controlled or initial.
onValueChange
(value: number) => void
default —
Fires from the scrub, key or typed entry that changed it, with the new value.
min
number
default 0
Lowest value; the tape ends here.
max
number
default 100
Highest value; the tape ends here.
step
number
default 1
The value's grid: one arrow key, one slow-scrub detent.
precision
number
default 0
Decimals shown and kept; never fewer than the step needs.
sensitivity
number
default 1
Scrub speed: one step per 6 / sensitivity px of a slow drag (also the tape's tick spacing).
accelerate
boolean
default true
Fast drags shift to coarser steps: ×10 above ~700 px/s, ×100 above ~1800 px/s on ranges of 1000 steps or more.
unit
string
default ""
A short unit shown after the number, e.g. "%", "px", "°".
ruler
boolean
default true
Show the tick bar along the bottom of the field while scrubbing, stepping, or hovering the label.
valueText
(value: number) => string
default —
The spoken value (aria-valuetext). Defaults to the value and its unit.
onScrubChange
(scrubbing: boolean, gear: number) => void
default —
Fires when a scrub starts, changes gear (1, 10 or 100) and ends.
accent
string
default "var(--accent-bright)"
The needle and the grip while scrubbing; any CSS colour.
name
string
default —
The input's form name.
size
"sm" | "md" | "lg"
default "md"
Field height 32, 36 or 44px, with matching type and tick sizes.
sound
boolean
default false
A tick for each value the scrub or a key passes (lower in a coarse gear, and at an end); only in answer to the visitor.
disabled
boolean
default false
Disables the field and the scrub.
className
string
default —
Classes for the root; it is w-full by default.