Hours Dial
Set a window of the day on a 24-hour face, with two handles that may run past midnight.
import { HoursDial, HoursDialValue } from '@youj/react'
Installation & usage
npm i @youj/reactFor 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 an hours dial for a stretch of the day: a sleep schedule, quiet hours, a shift, opening hours. The face is a whole day, midnight at the top and turning clockwise, with a ruler of quarter-hour ticks all the way round. A hollow handle marks the start and a solid one the end; the ticks between them light in the tone, and the center reads the length large in mono with the two times under it. For one bounded value on an arc, such as a temperature or a volume, use a Dial; for a single time, a Time Picker.
import { HoursDial } from '@youj/react'
<HoursDial
label="Sleep schedule"
caption="Asleep"
value={sleep}
onValueChange={setSleep}
/>The value is { start, end } in minutes after midnight (0–1439); an end before the start runs past midnight, so { start: 1350, end: 420 } is 22:30 to 07:00. step (15 minutes) is what an arrow key moves and what a drag snaps to, and largeStep (an hour) is what Page Up and Down move. The handles never meet: the window stays at least a step long and a step short of a whole day. tone colors the lit stretch (the accent, a chart color or neutral), caption puts a mono capital over the length, and the times read in the provider's locale (12- or 24-hour as it writes them). It's uncontrolled with defaultValue.
Description
A sleep schedule for weekdays and the weekend: drag either handle, or the lit band to move the whole night.
Code
hours-dial-demo.tsx, the Demo story. The component itself comes from the package.
Reference
Propsvalue, defaultValue, onValueChange… (11)
Props
| Prop | Type | |
|---|---|---|
value | HoursDialValue | – |
defaultValue | HoursDialValuedefault { start: 22 * 60 + 30, end: 7 * 60 } | { start: 22 * 60 + 30, end: 7 * 60 } |
onValueChange | (value: HoursDialValue) => void | – |
step | numberMinutes per arrow key and the snap of a drag; a divisor of 60 suits best. default 15 | 15 |
largeStep | numberMinutes per Page Up/Down. default 60 | 60 |
tone | HoursDialTone'accent''neutral''chart-1''chart-2''chart-3''chart-4''chart-5'The lit stretch's color. default 'accent' | 'accent' |
locale | stringDefault: the YoujProvider locale. | – |
label | stringAccessible name of the pair of handles. Default: the labels' "Time range". | – |
caption | ReactNodeA mono capital over the length: "Asleep". | – |
disabled | booleandefault false | false |
sound | booleanPlays the tick cue at every step. default true | true |
Other props pass through: extends ComponentProps<'div'>. | ||
StylingParts and data attributes
Styling
Parts: hours-dial (with data-tone, data-dragging set to start, end or window while a pointer holds it, and data-disabled), hours-dial-face, hours-dial-band, hours-dial-ruler, hours-dial-range, hours-dial-numerals, hours-dial-start and hours-dial-end (the handles, with data-dragging), hours-dial-center, hours-dial-label, hours-dial-value and hours-dial-times.
MotionKeyboard or click, drag, hover or drag · reduced motion
Motion
| Moment | Tokens | ||
|---|---|---|---|
| Keyboard or clickthe handles and the lit stretch glide to the new times together, the short way round, retargeting mid-flight | spring.snappy0.2s, bounce 0 | 0.2s, bounce 0 | |
| Draga handle, or the whole window, follows the pointer 1:1, snapping to the step | duration.instantease.standard80ms · cubic-bezier(0.2, 0, 0, 1) | 80mscubic-bezier(0.2, 0, 0, 1) | |
| Hover or dragthe handle grows a little | duration.fastease.standard140ms · cubic-bezier(0.2, 0, 0, 1) | 140mscubic-bezier(0.2, 0, 0, 1) |
Reduced motion
Every change jumps.
Reduced motion
The handles and the lit stretch jump to each new time.
AccessibilityKeyboard, focus
Accessibility
- It's a group named by
label(default: the labels' "Time range") holding two sliders, "Start" and "End", each valued in minutes after midnight. Their value text is the time and the window's length in the locale ("10:30 PM, 8 hours, 30 minutes in all"). - Arrows move a handle by the step, Page Up and Down by an hour, Home to midnight and End to the last step before it; steps wrap round midnight. A press on the face focuses the handle it moves, so the keys carry on from there.
- A clock turns clockwise in every script, so the face and its keys keep their direction under RTL: right and up move later. 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 (
hoursDial,hoursDialStart,hoursDialEnd,hoursDialValue), translated by the language packs.