Skip to the page
TACTILE UI

Kit part · Forms · Inputs · Numbers · Sliders & faders

Scrub field

A number you can type or drag, the way a pro tool’s value field works: an engraved ruler under the numerals slides beneath a fixed index as the value moves.

Element
<tui-scrub> + <input>
Needs
kit.css + kit.mjs
Rules
scrub.rules.md · 6
Finishes
Aluminium · Graphite · Porcelain · Black
Volumes
Tactile · Quiet
On this page
  1. Variants
  2. Every state, at once
  3. API
  4. Markup
  5. Accessibility
  6. How it’s built
  7. Rules
  8. Related parts
01

Variants

Plain · agent temperature
With a unit · kW, ms, tokens
RegionWeight
eu-west
us-east
ap-south
Compact · in a table cell
Inspector row · label on the left
Detents · half degrees
Error · what was typed stays
Disabled · set by policy
02

Every state, at once

Both finishes, side by side. Hover, pressed and focus are forced with .is-hover, .is-down and .is-focus; checked and disabled are real.

Aluminium

PartRestHoverScrubbingFocusAt a stopErrorDisabled
Field
Compact

Graphite

PartRestHoverScrubbingFocusAt a stopErrorDisabled
Field
Compact
03

API

NameKindValuesWhat it does
<tui-scrub>elementwraps one <input>The well: the numerals on top, the ruler along its floor. Builds itself around the input it is given.
<input>elementname · valueThe form control, kept real: its value posts; it becomes a text spinbutton with inputmode="decimal".
min · maxattribute0 · 100The stops. Values are clamped to them; typed values past them are too, with a knock at the stop.
stepattribute1What an arrow key, the wheel and a detent move by. The ruler ticks once per step.
precisionattributethe step’s decimalsDecimals the value keeps. A drag can land between steps down to this; Alt steps a tenth when it allows.
unit · unit-textattributee.g. "ms" · "milliseconds"Printed after the numerals, and spoken in aria-valuetext. unit-text is the spoken form when the printed one reads badly.
px-per-stepattribute1.5–8, from the rangeDrag rate at slow speed. Faster drags gain up to ×4, smoothly.
labelattributetextAn aria-label for the input when there is no printed label, as in a table cell.
data-detentattribute—Drags snap to whole steps; each one moves the ruler a notch and taps the phone’s motor where it has one.
data-lockattribute—Pointer lock once a drag passes its dead zone, for endless drags. Refused or unsupported, the drag carries on as usual.
data-boundattribute"min" · "max"Set while the value rests on a stop. Read it; the part writes it.
data-scrubbing · data-errorattribute—Set during a drag, and while typed text is not a number.
.tui-scrub--compactclass—26px numerals over a ruler of ticks only: for table cells and dense inspectors.
.tui-scrub-rowclasson the .tui-fieldThe label printed on the left, the field on the right: an inspector row.
.tui-scrub__gripclassadded to the labelThe field’s printed label becomes a drag handle too. Added by the part.
.value · .inputpropertynumber · <input>Read or set the number (setting fires nothing); reach the input.
input · changeeventon the <input>input while the value moves; change when it settles: drag released, key pressed, text taken.
Dragpointer3px dead zonePress the ruler or the label and drag; right is more. Under 3px it is a click, and you are typing. Esc puts the value back.
Shift · Altmodifier×10 · ×0.1For drags, arrow keys and the wheel alike.
↑ → · ↓ ←keyboard± stepStep up and down. While you are typing, ← and → move the caret instead.
PageUp · PageDown · Home · Endkeyboard±10 steps · min · maxBig steps and the stops. While typing, Home and End move the caret.
Enter · Escapekeyboardtake · revertTake what was typed, or put back the last good number.
Wheelpointerwhile focusedSteps the value only when the field has focus, so scrolling the page never changes it.
.is-hover · .is-down · .is-focusclasson <tui-scrub>Forced states, for documentation and specimens only.
04

Markup

<label class="tui-field">
  <span class="tui-label">Temperature</span>
  <tui-scrub min="0" max="2" step="0.1" precision="2">
    <input name="temperature" value="0.70">
  </tui-scrub>
  <span class="tui-hint">0 repeats itself; 2 wanders.</span>
</label>

<label class="tui-field">
  <span class="tui-label">Rate limit</span>
  <tui-scrub min="0" max="6000" step="10" unit="/min" unit-text="requests per minute" data-lock>
    <input name="rate" value="600">
  </tui-scrub>
</label>
import '/kit/kit.mjs';   // defines <tui-scrub>

const temp = document.querySelector('tui-scrub input[name="temperature"]');
temp.addEventListener('input', () => preview(Number(temp.value)));   // while it moves
temp.addEventListener('change', () => save(Number(temp.value)));     // when it settles

// Or read and set the number on the element; setting fires nothing.
const field = temp.closest('tui-scrub');
field.value = 0.2;

Needs kit.css and kit.mjs. How to install the kit.

05

Accessibility

  • The input is a role="spinbutton" with aria-valuenow, aria-valuemin, aria-valuemax and an aria-valuetext that carries the unit (“600 requests per minute”). Its name is the printed label that wraps it.
  • Everything a drag does, the keyboard does: arrows, Page keys, Home and End, typing. Dragging is never required.
  • Typed text that is not a number sets aria-invalid and a custom validity message, and the hint below says the range; nothing typed is thrown away.
  • Only the ruler and the label take touch-action: none: on a phone the page scrolls from anywhere else, and a tap on the numerals opens the decimal keypad.
  • The ruler and index are decoration for the number above them (aria-hidden). Reduced motion stops the ruler gliding and the stop’s knock; the number, the stop and the lit index still show.
06

How it’s built

One custom element around a real input. The ruler is a single strip whose ticks are three repeating backgrounds (fine every step, a longer one halfway, a long one at each round-numbered major) each an ink line with a lit line beside it, so the cuts read engraved; the numbers are spans placed along it. The strip moves by transform only, under a fixed index: a printed pointer over a hairline that turns amber with a lamp’s glow while you set the value. Past each end a heavy stop and hatching are printed on the strip, so at min or max the stop arrives under the index; a push past it knocks the hairline 1.5px and lets it settle. The window’s ends are masked away, as a tape curls over its drums. Drags use pointer capture, a 3px dead zone and a smoothed speed-to-gain curve capped at ×4; data-lock adds pointer lock.

07

Rules

scrub.rules.mdIn the brain

Type it, or drag the ruler. Keys move by the step, a drag reaches the precision, and the index lights only while you are setting it.

6 rules in this file, with the foundations they rest on and the anti-patterns that break them. Full rules ship in the brain with the Pass.

08

Field

Text entry in a recess, the label printed above it, and a hint that says how to fix an error.

Stepper

A small integer with − and + keys either side, in one well.

Knob

A rotary control for continuous or stepped values where space is square. Its knurl and pointer turn; its light does not.

Docs
Finish
Volume