Scrubber

A React component in Beamline's Form controls category, in the free sample.

A budget, a timeout or a position on a scale where the neighbourhood matters: the readout says how far under or over the named limit the value is, the ticks can be real measurements ("87% of requests at or under 90 ms"), hover shows where a press lands, a lens opens around the knob while it is held or focused (the knob never moves under it), and a release decides at once while the knob settles with the look's physics.

Use it for

  • Setting a limit or budget where it matters which side of it a value is on (latency, price, spend, retention).
  • Choosing a year, a version or a position in a history, where the values near the choice matter.

Not for

  • Exact values people type (number-field).
  • Two thumbs for a range, or a value with icons at the ends (slider).
  • Seeking in audio or video (scrub-bar).

Anatomy

  • head: label and readout (the value; with a threshold, a glyph and the distance to the named limit in words); the readout only grows while the room stays the same, so the value keeps its place; every run of words takes its own direction
  • well: the inset role, stretching past an end with the look's give; the zone past the threshold tinted by its tone
  • ticks: one per step while they keep 7 px apart; with a distribution, bars of the measured values where a value of its own sits (the lens spreads them, never changes their height)
  • probe: on hover, a hairline at the value a press there would set; over a mark's label it stands on that mark
  • rail: a native range input (keyboard, screen readers, forms) under the knob (the knob role, 3:1 boundary)
  • marks: labels under the well, each with a pin to its moment; their words fold by rank (the limit, then the ends, then priority); a folded mark keeps its pin
  • share: with a distribution, how many measured values sit at or under the value

States

  • rest (no lens, nothing moves)
  • hover (a mouse or pen shows the hairline where a press would land; nothing moves)
  • pressed and dragging (the lens opens around the knob, which is its fixed point and shows the step release would decide, within half a step of the pointer; it flattens while the hand moves fast; marks pull; past an end the well stretches)
  • settling (the value is decided; the knob glides there with the look's carry and bounce)
  • keyboard focus (the lens opens around the knob and follows it to each new value)
  • under, at and over the threshold (distance to the named limit in words, glyph and tone)
  • with a distribution (bars and the share at or under the value)
  • disabled
  • stacked (narrow: the readout under the label)
  • RTL (the scale runs from the right)

Keyboard

  • ←/→ and ↑/↓ step, or go to the next or previous stop when `stops` is given (→ follows the reading direction)
  • Page Up / Page Down jump to the next or previous mark (ten steps without marks)
  • Home / End go to the ends
  • Escape while dragging puts the value back

Motion

The lens opens on the snappy spring token and closes over the fast duration, times the look's weight, centred on the knob as drawn every frame, and flattens with the hand's speed. A release decides the value at once; the knob settles on the held spring with the look's carry and bounce (only after a throw); a key or a value from outside glides over the fast duration (a value arriving mid-glide retargets it); a tap or a mark settles critically damped on the held spring. Past an end the well stretches by the look's give. Only translate and scale move; rest is plain CSS. Reduced motion: no lens, no glide, no give; the readout carries the distance and the share.

Props

PropTypeDefaultDescription
label (required)ReactNode—Visible label or accessible name. Required.
value / defaultValue / onValueChangenumber—value: The chosen value, when controlled. defaultValue: Initial value when uncontrolled; defaults to min. onValueChange: Every change of the value: each preview while dragging, and the decided value at once on release, a key or a mark. To save only what was decided, use onValueCommit.
onValueCommit(value: number) => void—Once per decided change: a release, each key let go, a mark pressed, a screen reader's adjust; never a cancelled drag. Save here (debounce or confirm in the app if a save is costly).
onValueCancel(value: number) => void—A drag was cancelled (Escape, a lost pointer): the value is back to `value` and nothing was committed.
min / max / stepnumber—min: Lowest value. Defaults to 0. max: Highest value. Defaults to 100. step: Increment the value moves by. Defaults to 1.
marks(number | { value, label, priority })[]—Labelled ticks; numbers, or { value, label, priority }. Page Up/Down jump between them; they pull the value like detents within 6 px of where they are drawn. When labels crowd, a higher priority keeps its words; every mark keeps its pin. A mark at the threshold's value is the threshold's own (one label, its `label`, kept before the others).
stopsnumber[]—The values the arrows step between instead of `step` (the arrivals on a timeline: one key, one event).
threshold{ value, below?, above?, label?, belowTone?, aboveTone? }—A limit: the readout says how far under or over it the value is, the well past it carries its tone.
distribution / distributionLabel / showSharenumber[] / string / boolean—distribution: Measured values along the scale (the last day's latencies): the ticks become their distribution and the readout says how many sit at or under the value. distributionLabel: What the distribution counts, for the readout ("requests" → "92 % of requests at or under 90 ms"). showShare: Shows the share at or under the value under the scale; defaults to true. False keeps the distribution as the scale only.
format / formatOptions / prefix / suffix(value) => string / Intl.NumberFormatOptions / string / string—format: Turns a value into its text ("70 ms"). Wins over the plain settings below. formatOptions: Plain formatting a server component can pass: Intl options for the number. prefix: Text before the formatted number ("$"). suffix: Text after the formatted number (" ms").
valueText(value: number) => string—What a screen reader hears for the value; defaults to the value, the distance to the limit and the share.
lensnumber2.5How strongly the lens magnifies around the knob while it is held or has keyboard focus (0 off). Default 2.5.
showLabelbooleantrueShows the label visually while keeping its accessible name; defaults to true.
disabled / name / dirboolean / string / "ltr" | "rtl"—disabled: Prevents interaction. name: Field name for native form submission (the native range input underneath carries it). dir: Reading direction; inherits the surrounding direction when omitted.
valuenumber—The chosen value, when controlled.
defaultValuenumber—Initial value when uncontrolled; defaults to min.
onValueChange((value: number) => void)—Every change of the value: each preview while dragging, and the decided value at once on release, a key or a mark. To save only what was decided, use onValueCommit.
minnumber—Lowest value. Defaults to 0.
maxnumber—Highest value. Defaults to 100.
stepnumber—Increment the value moves by. Defaults to 1.
distributionnumber[]—Measured values along the scale (the last day's latencies): the ticks become their distribution and the readout says how many sit at or under the value.
distributionLabelstring—What the distribution counts, for the readout ("requests" → "92 % of requests at or under 90 ms").
showShareboolean—Shows the share at or under the value under the scale; defaults to true. False keeps the distribution as the scale only.
format((value: number) => string)—Turns a value into its text ("70 ms"). Wins over the plain settings below.
formatOptionsNumberFormatOptions—Plain formatting a server component can pass: Intl options for the number.
prefixstring—Text before the formatted number ("$").
suffixstring—Text after the formatted number (" ms").
disabledboolean—Prevents interaction.
namestring—Field name for native form submission (the native range input underneath carries it).
dir"ltr" | "rtl"—Reading direction; inherits the surrounding direction when omitted.
classNamestring—Classes on the documented visual root.
classNamesPartial<Record<"root" | "label" | "head" | "mark" | "tick" | "readout" | "zone" | "mark…—Classes for the named visual parts.
styleCSSProperties—Inline styles on the documented visual root.
refRef<HTMLDivElement>—Receives the root element.

Used in

Import

import { Scrubber } from "@beamline/scrubber";

Get it

Scrubber is part of Beamline UI. Install the parts you need in your React app as compiled packages or editable source. Scrubber is included in the free MIT sample. Get Beamline · Connect your agent

More in Form controls

  • Target table: Rows of repeated rounds with typed targets (a load × a count, a count range, a time, a load held for a time), each row drawn as a bar beside its numbers…
  • Color Palette: A wheel of preset colours to pick from: twelve hues around the ring, their tints inward, white at the middle; the chosen swatch lifts and carries a check.
  • Rich text editor: A Notion-grade writing surface: slash menu for every block, a formatting toolbar on selection, drag-to-move blocks, nesting, markdown shortcuts, paste…
  • Allocation editor: Parts of a fixed whole edited as transfers: an ordered strip whose boundaries drag or step between neighbours and a roster of exact amounts where typing…
  • Radio cards: One choice among rich options as cards with optional media, icon, detail and a figure; one selection ring follows the stable choice.
  • Calendar: Month grids for picking a day or a range: a real grid with arrows by day and week, Page keys by month, closed days, today's dot, and a range span that…
  • Availability rule editor: When someone (or something) can be booked: hours for each day of the week, one or more ranges a day, a day turned off, a day's hours copied to the others…
  • Recurrence editor: How something repeats, set in plain controls and said back in a sentence: every N days, weeks, months or years; which weekdays; in a month, on a date or…
  • Signature pad: A pad for a drawn signature whose ink follows a stylus's pressure (and thins with speed under a mouse or finger); undo, replay, PNG or SVG export, and…
  • Image cropper: Frame a picture before it is saved: a fixed window (square, round for avatars, wide for covers, or free with handles) over the picture, which you drag…
  • Input Dissolve: A one-line field whose text breaks into specks and drifts off once it is sent, last letter first; the field is empty and ready again.
  • Password field: A password field with a reveal control, and a strength meter when a password is being created.
  • Card field: A payment card in one field: the number groups as it is typed and names its network, the expiry and security code follow on their own as each part…
  • File drop zone: A generous target for files: drop or choose, each checked against type, size and count with the reason when turned away; uploads show progress and can be…
  • Slider: A value or range on a known scale: the thumb grows under the finger and shows its value while dragged or focused; marks, end icons and a value readout.
  • Rating: A score on a small scale: stars that fill as you point (halves too) and light one after another when chosen, with the word for the score beside them…
  • Date range picker: A reporting range: presets on one side and two months on the other (one on a phone); the trigger names the preset in use, and the footer counts the days…
  • OTP input: A verification code in separate boxes backed by one real field, so paste, SMS autofill and Backspace work; optional groups like 123–456.
  • Segmented control: Two to five views or ranges of the same content (1D / 1W / 1M, List / Board): a radio group whose raised thumb slides to the choice.
  • Stage field: A record's status as its stages in order, editable in place. Stages before the current one read as passed (gone through, never "complete"); only the…
  • Layout picker: Shared record layouts for one page. Each layout says where it's used ("Used on 3 pages: Deals, this page, Forecast") and how many fields it shows, and a…
  • Tooth picker: Teeth and their surfaces for one procedure. The arch by Universal number as you face the patient (upper 1–16, lower 32–17; supernumerary teeth on their…
  • Colour picker: A swatch that opens a picker: saturation-brightness plane, hue strip, HEX/RGB/HSL/OKLCH value to type or copy, the screen eyedropper where available…
  • Emoji picker: An emoji chosen from a search and a grid. The trigger shows the chosen emoji and opens a search above the emoji by group, with the recently used first…
  • Chip group: Quick filters as chips: a chosen chip fills and grows a check, counts show what each would return, and extra chips fold behind “+N”.
  • Shortcut recorder: Lets people set their own shortcut: press the keys, see them as keycaps; a clash or a browser-kept shortcut asks first. ShortcutCheatsheet lists every…
  • Mention input: A composer where @people and #channels become single tokens with suggestions at the caret; the value keeps the text and where each mention sits.
  • Tag input: Short free-form values as tags: Enter, comma or Tab adds, a pasted list adds them all, Backspace twice removes the last; duplicates and invalid values…
  • Multi-select: Several values from a known list as removable chips in the field; the list has a search field (for long lists), checkable rows and a count with Clear…
  • Tree select: A field that picks from a tree: departments and teams, categories and subcategories, folders, regions and cities; the list opens as an indented tree…
  • Combobox: One value from a long list found by typing (time zones, countries, customers): ranked matches with the match emphasised, keywords, optional group…
  • Phone input: A phone number with its country: searchable picker with country and dialling codes, “+44…” switches the country, the number groups as typed, and the…
  • Date picker: One date in a form: a field that opens the month grid under it with focus inside, picks and closes; Today and Clear below, optional clear button.
  • Time picker: A time of day as hour and minute segments, typed or stepped, 12- or 24-hour; the clock opens a list of times at the step.
  • Reminder picker: Snooze or remind, at an exact time. Two named actions on one picker: Snooze hides the item until then, Remind me keeps it in view and reminds at that…
  • Number field: A bounded number with − and +: arrows and Page keys step, typing is read in the locale and clamped on leaving, limits can be explained, and the label can…
  • Stock adjust: An on-hand count changed with its reason: received, recounted, damaged, lost or returned; by an amount or to a new count; in the item's unit or in packs…
  • Inline edit: Text, a number or an amount of money that becomes a field in the same place: Enter (or ⌘Enter when multiline) saves, Escape cancels, leaving saves…
  • Search field: The search entry point: magnifier, clear button, Escape to clear, a shortcut hint and an optional live border beam.
  • Switch: A setting that applies at once: a thumb that slides on a spring and stretches under the finger, with an optional label before or after.
  • Form: Validation wiring for react-hook-form (and zod) on the system's own fields: each field already links its label, help and error, so FormField hands over…
  • Select: One choice from a short known list, in the same frame as every text field: label, help, error, option groups and details.
  • Toggle group: Pressable toggles where one or several can be on: alignment, bold and italic, view options; bare for toolbars or framed.
  • Input: A single-line text field with its label, help and error wired for assistive tech, three sizes and adornments. With complete or emailDomains it offers…
  • Checkbox: A yes/no choice with an optional label and help, including the mixed state for select-all; the check draws itself in.
  • Radio group: One choice from a short visible set, each option with an optional description, vertical or in a row.
  • Textarea: Multi-line plain text that grows with what is typed up to a limit, with an optional character count.
  • Label: The text label tied to a form control, with a required marker that screen readers announce.
  • Value grip: A grip on a scale your screen draws (a bar's end, a flag, a markup's edge): drag it, or use the arrows, to a value snapped to its step; the value arrives…
  • Count adjust: A count of whole things against its whole (received of ordered, credits of bought), set by hand: what is on record stays solid, the change is drawn as…

Part of Beamline UI: polished, editable React components and complete screens for custom applications. Build your own style from any look; tokens, fonts, radii, motion; not only colours.