Skip to content

Dial

Adjust a value on a circular scale, with a measured value and setpoints for reference.

import { Dial, DialBand, DialMark } from '@youj/react'

Installation & usage

npm i @youj/react

For 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 dial for a bounded value people turn: a thermostat, a volume, a fan speed, a brightness. The arc runs three quarters of the way round, from the lower left to the lower right, ticked at every step, with the value as an ink knob on the band and large in mono in the middle. Give it a measured value and the stretch between the two lights in its tone, heating up to the target or cooling down to it. For a value along a line, use a Slider; to show a score that isn't set by hand, a Gauge. For a window of the day that may run past midnight, such as a sleep schedule, use an Hours Dial.

import { Dial } from '@youj/react'

<Dial
  label="Target temperature"
  caption="Heating to"
  value={target}
  onValueChange={setTarget}
  min={12}
  max={28}
  step={0.5}
  current={19.8}
  tone="warm"
  marks={[{ value: 17, label: 'Night' }, { value: 21, label: 'Morning' }]}
  format={{ style: 'unit', unit: 'celsius', maximumFractionDigits: 1 }}
/>

min, max and step bound the value, which snaps to the step; largeStep (ten steps by default) is what Page Up and Down take. current shows a measured value: a marker inside the band, "Now 19.8°C" under the figure, and the stretch between it and the value lit. tone colors that stretch: warm and cool suit heating and cooling, and the accent, a chart color or neutral suit anything else. marks put small rings on the ruler for setpoints, such as a schedule's. format sets how the figures read, and caption puts a mono capital over the figure. It's uncontrolled with defaultValue.

Reference

Propsvalue, defaultValue, onValueChange… (18)

Props

Dial props
PropType
valuenumber–
defaultValuenumber–
onValueChange(value: number) => void–
minnumber

default 0

0
maxnumber

default 100

100
stepnumber

default 1

1
largeStepnumber

Per Page Up/Down and Shift+arrow.

default 10

10
currentnumber

A measured value to show against the setting: a room's temperature.

–
marksDialMark[]

Setpoints on the ruler.

default []

[]
toneDialTone
'accent''warm''cool''neutral''success''warning''danger''chart-1''chart-2''chart-3''chart-4''chart-5'

The lit stretch's color. warm and cool suit heating and cooling; success, warning and danger suit bands.

default 'accent'

'accent'
formatIntl.NumberFormatOptions

Intl.NumberFormat options for the figures: { style: 'unit', unit: 'celsius' }. Default: whole numbers.

–
localestring

Default: the YoujProvider locale.

–
labelstring

Accessible name. Default: the labels' "Dial".

–
captionReactNode

A mono capital over the figure: "Heating to".

–
soundboolean

Plays the tick cue at every step.

default true

true
variant'default' | 'ticks'

ticks draws the arc as a ring of radial ticks that light up to the value, with no band or knob.

default 'default'

'default'
ticksnumber

How many ticks the ticks variant draws.

default 55

55
bandsDialBand[]

Tones by value, in ascending order: the last band whose from the value has reached sets the tone, over tone.

default []

[]
Other props pass through: extends SliderPrimitive.Root.Props<number>.
StylingParts and data attributes

Styling

Parts: dial (with data-variant, data-tone and data-dragging; data-tone is the band's tone when bands set one), dial-face, dial-arc, dial-ruler, dial-track, dial-range, dial-mark, dial-current, dial-knob, dial-thumb, dial-center, dial-label, dial-value and dial-now. The ticks variant draws dial-ticks, a dial-tick each, and dial-focus in place of the ruler, band and knob.

MotionKeyboard or click, drag, hover, focus or drag · reduced motion

Motion

Motion tokens
MomentTokens
Keyboard or clickthe knob and the lit stretch glide to the new value together, retargeting mid-flight
spring.snappy

0.2s, bounce 0

0.2s, bounce 0
Dragthe knob follows the pointer 1:1, snapping to the step
duration.instantease.standard

80ms · cubic-bezier(0.2, 0, 0, 1)

80mscubic-bezier(0.2, 0, 0, 1)
Hover, focus or draga halo in the tone comes up round the knob
duration.fastease.standard

140ms · cubic-bezier(0.2, 0, 0, 1)

140mscubic-bezier(0.2, 0, 0, 1)
Ticks: keyboard or clickthe lit ticks follow the value on the same spring, reaching outward as the edge passes
spring.snappy

0.2s, bounce 0

0.2s, bounce 0
Ticks: band changethe lit ticks cross-fade to the new tone
duration.fastease.standard

140ms · cubic-bezier(0.2, 0, 0, 1)

140mscubic-bezier(0.2, 0, 0, 1)

Reduced motion

Every change jumps.

Reduced motion

The knob and the lit stretch, or the lit ticks, jump to each new value.

AccessibilityKeyboard, focus

Accessibility

  • It's a Base UI slider under the arc: a native range input named by label (default: the labels' "Dial"), with the measured value spoken beside the setting ("21.5 °C, now 19.8 °C"). The marks are its description ("Night: 17 °C; Morning: 21 °C").
  • Arrows step, Page Up and Down take large steps, and Home and End jump to the ends. A pointer anywhere on the band drags the knob round and focuses the dial, so the keys carry on from there.
  • A dial turns clockwise in every script, so the arc and its keys keep their direction under RTL: right and up raise the value. The text in the center follows the page.
  • Every step plays the tick cue, like a detent, behind sound (on by default).
  • Its words come from the labels (dial, dialNow, dialValueNow, dialMark), translated by the language packs.