wts-timepicker
v19.0.0
Published
Dependency-free, accessible, framework-agnostic clock-face time picker and Web Component.
Downloads
122
Maintainers
Readme
wts-timepicker
A dependency-free, accessible clock-face time picker for JavaScript, TypeScript, Angular, React, Vue, Svelte, and plain HTML.
The package provides two APIs:
WtsTimepicker, an imperative DOM controller; and<wts-timepicker>, a form-associated Web Component.
It has no runtime dependencies and importing either entry point is safe during server-side rendering.
Install
npm install wts-timepickerJavaScript and TypeScript
<input id="meeting-time" value="02:45 pm">
<div id="picker"></div>import { WtsTimepicker } from 'wts-timepicker';
const picker = new WtsTimepicker('#picker', {
trigger: '#meeting-time',
value: '02:45 pm',
format: 12,
minutesGap: 5,
appearance: 'dialog',
onChange(value) {
console.log(value);
},
});
picker.open();
picker.setValue('04:30 pm');
picker.destroy();The default styles are injected automatically. To manage styles yourself:
import { WtsTimepicker } from 'wts-timepicker';
import 'wts-timepicker/styles.css';
new WtsTimepicker('#picker', { injectStyles: false });Web Component
Import the registration entry once:
import 'wts-timepicker/element';Then use the element in HTML:
<form>
<wts-timepicker
name="meetingTime"
required
value="02:45 pm"
min="09:00"
max="17:00"
step="15"
format="12"
minutes-gap="5"
appearance="inline"
auto-close="false"
></wts-timepicker>
<button>Submit</button>
</form>Omit value, or set it to an empty string, when the form should start
unselected. The element then exposes native-style form, labels,
validity, validationMessage, willValidate, checkValidity(), and
reportValidity() APIs. A required empty picker is invalid until a time is
committed. The read-only clockFace type does not submit a form value.
Form submission always uses the stable 24-hour HH:mm representation, while
value retains the configured package format and displayValue contains the
locale-aware visible text.
const picker = document.querySelector('wts-timepicker');
picker.value; // "02:45 pm"
picker.canonicalValue; // "14:45"
picker.formValue; // "14:45"
picker.displayValue; // locale-aware
picker.valueAsTime; // { hour: 14, minute: 45, second: 0 }
picker.valueAsMinutes; // 885When min is later than max, the allowed range crosses midnight. For
example, min="22:00" max="02:00" allows late-night and early-morning times.
step is expressed in minutes and is anchored to min, or midnight when no
minimum is supplied.
Custom dropdown mode
Use picker-mode="dropdown" for a compact custom dropdown UI instead of the
clock dial. It uses accessible combobox/listbox semantics rather than native
<select> elements, supports full keyboard navigation, and shares the same
constraints, localization, events, form value, and validation behavior.
<wts-timepicker
picker-mode="dropdown"
appearance="inline"
value="02:45 pm"
min="09:00"
max="17:00"
step="15"
></wts-timepicker>For dialog presentation:
<button id="open-picker" type="button">Choose time</button>
<wts-timepicker id="picker" value="02:45 pm"></wts-timepicker>
<script type="module">
import 'wts-timepicker/element';
const picker = document.querySelector('#picker');
document
.querySelector('#open-picker')
.addEventListener('click', () => picker.showPicker());
picker.addEventListener('change', (event) => {
console.log(event.detail.value);
});
</script>Framework use
Web Components work directly in Vue and Svelte. React users should set element
properties through a ref when a non-string value is needed. Angular users can
add CUSTOM_ELEMENTS_SCHEMA to the consuming component or module and import
wts-timepicker/element once.
The imperative controller is also available in every framework and is useful when the framework should own the surrounding input.
Options
| Option | Default | Description |
| --- | --- | --- |
| value | current local time (controller), empty (element) | A Date, formatted time string, or empty string |
| min | none | Earliest selectable time; accepts configured or canonical format |
| max | none | Latest selectable time; supports ranges crossing midnight |
| step | 1 | Selectable minute interval from 1 through 720 |
| format | 12 | 12 or 24 hour output |
| minutesGap | 5 | Visible minute-label interval, from 1 to 30 |
| locale | none | Locale for visible time, numerals, and day periods |
| labels | English labels | Accessible hour, minute, selectHour, selectMinute, period, and currentTime labels |
| type | timepicker | Interactive timepicker or live clockFace |
| pickerMode | clock | Interactive clock dial or custom dropdown |
| appearance | dialog | Modal dialog or inline presentation |
| headerEnabled | true | Displays hour and minute fields |
| footerEnabled | true | Displays Cancel and Apply |
| positionX | left | left or right inline alignment |
| positionY | auto | auto, top, or bottom inline placement |
| closeOnEscape | true | Cancels the picker on Escape |
| autoClose | true | Commits after a minute is selected |
| disabled | false | Disables interaction |
| readOnly | false | Prevents edits |
| injectStyles | true | Injects the bundled styles |
| trigger | null | Element or selector that opens the picker |
Callbacks are available as onInput, onChange, onOpen, and onClose.
The Web Component exposes labels through attributes such as hour-label,
minute-label, select-hour-label, select-minute-label, period-label,
and current-time-label.
<wts-timepicker
appearance="inline"
format="24"
locale="de-DE"
hour-label="Stunde"
minute-label="Minute"
select-hour-label="Stunde auswählen"
select-minute-label="Minute auswählen"
></wts-timepicker>Controller methods
picker.open();
picker.close(); // cancel
picker.close(true); // commit
picker.apply();
picker.cancel();
picker.setValue('14:30');
picker.setOptions({ format: 24 });
picker.destroy();The current committed values are available through picker.value and
picker.time.
Clock digits use a single keyboard tab stop. Use the arrow keys to move and select, or Home and End to jump to the first or last value. Escape cancels an open picker and returns focus to its trigger.
Events
Both APIs emit:
inputwhen the draft selection changes;changewhen a value is committed;wts-timepicker-openwhen the picker opens; andwts-timepicker-closewhen it closes.
input and change are composed CustomEvent instances:
pickerElement.addEventListener('change', (event) => {
console.log(event.detail.value);
console.log(event.detail.canonicalValue); // "21:15"
console.log(event.detail.displayValue); // locale-aware
console.log(event.detail.time); // { hour, minute, second }
});Styling
The main CSS custom properties are:
wts-timepicker {
--wts-timepicker-accent: #6d28d9;
--wts-timepicker-accent-contrast: #fff;
--wts-timepicker-background: #fff;
--wts-timepicker-border: #6d28d9;
--wts-timepicker-color: #202124;
--wts-timepicker-size: 300px;
}Web Component internals can be customized without reaching into its Shadow DOM:
wts-timepicker::part(panel) {
border-radius: 20px;
}
wts-timepicker::part(apply-button) {
font-weight: 800;
}
wts-timepicker::part(digit) {
font-variant-numeric: tabular-nums;
}Available parts include root, overlay, panel, header, fields,
hour-field, minute-field, period, period-button, face, digit,
hour-digit, minute-digit, hand, footer, cancel-button,
apply-button, error, dropdown, dropdown-field, dropdown-trigger,
dropdown-menu, and dropdown-option.
Pure time utilities
Parsing, formatting, clock-item generation, and hand geometry can be used without constructing DOM:
import {
clockHandAngles,
formatTime,
parseTime,
} from 'wts-timepicker';
const time = parseTime('09:15 pm', 12);
if (time) {
console.log(formatTime(time, 24)); // 21:15
console.log(clockHandAngles(time));
}Migration
Version 19 replaces the Angular component and directive with portable APIs. See MIGRATION.md for the Angular migration.
