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.
Contours
Fieldline · Ridge survey
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.
| Prop | Type | Default | Description |
|---|---|---|---|
| label | string | — | The field's name: shown on the left, and the handle you scrub. |
| value / defaultValue | number | — / 0 | The value, controlled or initial. |
| onValueChange | (value: number) => void | — | Fires from the scrub, key or typed entry that changed it, with the new value. |
| min | number | 0 | Lowest value; the tape ends here. |
| max | number | 100 | Highest value; the tape ends here. |
| step | number | 1 | The value's grid: one arrow key, one slow-scrub detent. |
| precision | number | 0 | Decimals shown and kept; never fewer than the step needs. |
| sensitivity | number | 1 | Scrub speed: one step per 6 / sensitivity px of a slow drag (also the tape's tick spacing). |
| accelerate | boolean | 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 | "" | A short unit shown after the number, e.g. "%", "px", "°". |
| ruler | boolean | true | Show the tick bar along the bottom of the field while scrubbing, stepping, or hovering the label. |
| valueText | (value: number) => string | — | The spoken value (aria-valuetext). Defaults to the value and its unit. |
| onScrubChange | (scrubbing: boolean, gear: number) => void | — | Fires when a scrub starts, changes gear (1, 10 or 100) and ends. |
| accent | string | "var(--accent-bright)" | The needle and the grip while scrubbing; any CSS colour. |
| name | string | — | The input's form name. |
| size | "sm" | "md" | "lg" | "md" | Field height 32, 36 or 44px, with matching type and tick sizes. |
| sound | boolean | 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 | false | Disables the field and the scrub. |
| className | string | — | Classes for the root; it is w-full by default. |