timepicker-ui

Modern time picker library built with TypeScript. Works with any framework or vanilla JavaScript.

npm version downloads license

Live DemoDocumentationChangelog

Upgrading from v2? Check the upgrade guide below.

Features

Known Limitations

This project is actively maintained. Some areas planned for improvement:

Contributions welcome! Feel free to open an issue or PR.

Installation

npm install timepicker-ui

Important: Global CSS Required

Your app needs this global CSS rule for correct styling:

*,
*::before,
*::after {
  box-sizing: border-box;
}

Most projects include this by default.

Quick Start

Basic Usage

<input id="timepicker" type="text" />
import { TimepickerUI } from "timepicker-ui";
import "timepicker-ui/main.css";

const input = document.querySelector("#timepicker");
const picker = new TimepickerUI(input);
picker.create();

With Options

const picker = new TimepickerUI(input, {
  theme: "dark",
  clockType: "24h",
  animation: true,
  backdrop: true,
  onConfirm: (data) => {
    console.log("Selected time:", data);
  },
});
picker.create();

React Example

import { useEffect, useRef } from "react";
import { TimepickerUI } from "timepicker-ui";
import "timepicker-ui/main.css";

function TimePickerComponent() {
  const inputRef = useRef<HTMLInputElement>(null);

  useEffect(() => {
    if (inputRef.current) {
      const picker = new TimepickerUI(inputRef.current, {
        onConfirm: (data) => {
          console.log("Time selected:", data);
        },
      });
      picker.create();

      return () => picker.destroy();
    }
  }, []);

  return <input ref={inputRef} type="text" />;
}

Configuration

Full documentation available at timepicker-ui.vercel.app/docs

Key Options

Option Type Default Description
clockType 12h / 24h 12h Clock format
theme string basic UI theme (9 themes available)
animation boolean true Enable animations
backdrop boolean true Show backdrop overlay
editable boolean false Allow manual input editing
mobile boolean false Force mobile version
disabledTime object undefined Disable specific hours/minutes
incrementHours number 1 Hour increment step
incrementMinutes number 1 Minute increment step
switchToMinutesAfterSelectHour boolean true Auto-switch to minutes after hour
okLabel string OK OK button text
cancelLabel string CANCEL Cancel button text
onConfirm function undefined Callback when time is confirmed
onCancel function undefined Callback when cancelled
onOpen function undefined Callback when picker opens
onUpdate function undefined Callback when time is updated
onSelectHour function undefined Callback when hour is selected
onSelectMinute function undefined Callback when minute is selected
onSelectAM function undefined Callback when AM is selected
onSelectPM function undefined Callback when PM is selected
onError function undefined Callback when error occurs

Themes

Available themes: basic, crane-straight, crane-radius, m3, dark, glassmorphic, pastel, ai, cyberpunk

import "timepicker-ui/main.css"; // Required base styles
import "timepicker-ui/theme-dark.css"; // Specific theme

const picker = new TimepickerUI(input, {
  theme: "dark",
});

Disabled Time

const picker = new TimepickerUI(input, {
  disabledTime: {
    hours: [1, 3, 5, 8],
    minutes: [15, 30, 45],
    interval: "10:00 AM - 2:00 PM",
  },
});

Inline Mode

const picker = new TimepickerUI(input, {
  inline: {
    enabled: true,
    containerId: "timepicker-container",
    showButtons: false,
    autoUpdate: true,
  },
});

API Methods

Instance Methods

const picker = new TimepickerUI(input, options);

picker.create(); // Initialize
picker.open(); // Open programmatically
picker.close(); // Close
picker.destroy(); // Clean up
picker.getValue(); // Get current time
picker.setValue("14:30"); // Set time
picker.update({ options }); // Update configuration

Static Methods

TimepickerUI.getById("my-id"); // Get instance by ID
TimepickerUI.getAllInstances(); // Get all instances
TimepickerUI.destroyAll(); // Destroy all instances

Events

Listen to timepicker events using the new EventEmitter API (recommended) or the legacy DOM events (deprecated, will be removed in v4):

const picker = new TimepickerUI(input);
picker.create();

picker.on("confirm", (data) => {
  console.log("Time confirmed:", data);
});

picker.on("cancel", (data) => {
  console.log("Cancelled:", data);
});

picker.on("open", () => {
  console.log("Picker opened");
});

picker.on("update", (data) => {
  console.log("Time updated:", data);
});

picker.on("select:hour", (data) => {
  console.log("Hour selected:", data.hour);
});

picker.on("select:minute", (data) => {
  console.log("Minute selected:", data.minutes);
});

picker.on("select:am", (data) => {
  console.log("AM selected");
});

picker.on("select:pm", (data) => {
  console.log("PM selected");
});

picker.on("error", (data) => {
  console.log("Error:", data.error);
});

picker.once("confirm", (data) => {
  console.log("This runs only once");
});

picker.off("confirm", handler);

Legacy DOM Events (Deprecated)

Note: DOM events (e.g., timepicker:confirm) are deprecated and will be removed in v4. Please migrate to the new EventEmitter API shown above.

input.addEventListener("timepicker:confirm", (e) => {
  console.log("Time:", e.detail);
});

input.addEventListener("timepicker:cancel", (e) => {
  console.log("Cancelled");
});

Available legacy events: timepicker:open, timepicker:cancel, timepicker:confirm, timepicker:update, timepicker:select-hour, timepicker:select-minute, timepicker:select-am, timepicker:select-pm, timepicker:error

Upgrade Guide: v2 → v3

Breaking Changes

1. CSS must be imported manually

// v3 - Required
import "timepicker-ui/main.css";

2. Event names changed

// v2
input.addEventListener("show", ...);
input.addEventListener("accept", ...);

// v3
input.addEventListener("timepicker:open", ...);
input.addEventListener("timepicker:confirm", ...);

3. Use callbacks instead of events

// v3 - Recommended
const picker = new TimepickerUI(input, {
  onConfirm: (data) => console.log(data),
  onCancel: (data) => console.log("Cancelled"),
});

4. destroy() behavior

// v2 - Removed input from DOM
picker.destroy();

// v3 - Only destroys picker, keeps input
picker.destroy();

New in v3

Migration to EventEmitter (v3.x)

Starting in v3.x, we recommend using the new EventEmitter API instead of DOM events:

// Old way (deprecated, will be removed in v4)
input.addEventListener("timepicker:confirm", (e) => {
  console.log(e.detail);
});

// New way (recommended)
picker.on("confirm", (data) => {
  console.log(data);
});

Benefits:

Framework Integration

React

import { useEffect, useRef } from "react";
import { TimepickerUI } from "timepicker-ui";
import "timepicker-ui/main.css";

function App() {
  const inputRef = useRef(null);

  useEffect(() => {
    if (!inputRef.current) return;
    const picker = new TimepickerUI(inputRef.current);
    picker.create();
    return () => picker.destroy();
  }, []);

  return <input ref={inputRef} placeholder="Select time" />;
}

Vue 3

<template>
  <input ref="pickerInput" placeholder="Select time" />
</template>

<script setup>
import { onMounted, ref } from "vue";
import { TimepickerUI } from "timepicker-ui";
import "timepicker-ui/main.css";

const pickerInput = ref(null);

onMounted(() => {
  if (!pickerInput.value) return;
  const picker = new TimepickerUI(pickerInput.value);
  picker.create();
});
</script>

Angular

import { Component, ElementRef, ViewChild, AfterViewInit } from "@angular/core";
import { TimepickerUI } from "timepicker-ui";

@Component({
  selector: "app-root",
  template: `<input #timepickerInput placeholder="Select time" />`,
})
export class App implements AfterViewInit {
  @ViewChild("timepickerInput") inputRef!: ElementRef<HTMLInputElement>;

  ngAfterViewInit() {
    const picker = new TimepickerUI(this.inputRef.nativeElement);
    picker.create();
  }
}

Add to angular.json styles:

"styles": ["src/styles.css", "timepicker-ui/main.css"]

Development

Development tooling is in the app/ directory. See app/README.md for details.

License

MIT © Piotr Glejzer

Contributing

Contributions welcome! Check the issues page.

Browser Support

Chrome 60+, Firefox 55+, Safari 12+, Edge 79+, iOS Safari 12+, Chrome Android 60+

Support