wts-timepicker

Dependency-free, accessible, framework-agnostic clock-face time picker and Web Component.
1,458
Install
npm install wts-timepicker
Latest Version:19.0.0
License:MIT
Last Updated:Aug 5, 2026
Links: GitHub  ·  npm
Maintainer: suman_mandal

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-timepicker

JavaScript 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; // 885

When 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:

  • input when the draft selection changes;
  • change when a value is committed;
  • wts-timepicker-open when the picker opens; and
  • wts-timepicker-close when 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.

Related Packages

wts-otp

Zero-dependency, accessible OTP, PIN, and verification-code input for JavaScript...

1,532 0
jervis-icons

Universal icon/image web component that works with any framework

30,773
ff-widget

FeedForward Widget - Universal Web Component for feedback collection. Works with...

2,421
@neongate-ai/orbz

A framework-agnostic, customizable AI voice orb built as a strict, SSR-safe web...

3,048 7
orbo-voice

A framework-agnostic, customizable AI voice orb built as a strict, SSR-safe web...

256 7

Version History

Version Released License
19.0.0 MIT
18.0.1 MIT
18.0.0 MIT
3.0.9 MIT
3.0.8 MIT