EasyEpoch

A lightweight datetime picker in vanilla JavaScript with zero dependencies.

npm version MIT License
Buy me a coffee
$ npm install easyepoch
Examples

Theming

Switch between built-in light and dark themes at runtime with setTheme().

Current theme: dark
const picker = new EasyEpoch({ theme: 'dark' }); // Switch at runtime picker.setTheme('light'); picker.setTheme('dark'); // Or pass a custom theme object picker.setTheme({ bg: '#0a0a0a', primary: '#ff6b6b', secondary: '#ffd93d', accent: '#ff6b6b', text: '#f0f0f0', });

Basic Usage

Create a picker, open it with a button, and listen for the selected date.

Click the button to select a date...
const picker = new EasyEpoch(); picker.on('submit', (date, readableDate) => { console.log(readableDate); // "7th February 2026 3:30 PM" }); document.querySelector('button').addEventListener('click', () => { picker.open(); });

Keyboard Shortcuts

Every picker on the page supports keyboard navigation while open. Try opening any demo and pressing the keys below.

Move the selection back / forward by one day Move by one week Home End Jump to the first / last day of the visible month PgUp PgDn Move by one month (clamps to last valid day) Shift+PgUp / PgDn Move by one year Enter Submit (same as OK) Esc Cancel and close
// Arrow keys are not intercepted while the time input has focus, // so users can edit hours/minutes normally. Out-of-range cells // (see minDate / maxDate) are skipped automatically.

Bound to Element

Attach the picker to a specific container element instead of the body.

const picker = new EasyEpoch('#my-container', { zIndex: 10 }); picker.on('submit', (date, readableDate) => { document.querySelector('input').value = readableDate; });

Compact Mode

Hide the large date display header for a smaller, more compact layout.

Click the button to try compact mode...
const picker = new EasyEpoch({ compactMode: true }); picker.on('submit', (date, readableDate) => { console.log(readableDate); });

Date Only (No Time)

Disable the time picker section when you only need a date.

Click the button to pick a date without time...
const picker = new EasyEpoch({ disableTimeSection: true }); picker.on('submit', (date, readableDate) => { console.log(readableDate); });

Pre-selected Date

Initialize the picker with a specific date already selected.

Opens with Dec 31, 2026 pre-selected...
const picker = new EasyEpoch({ selectedDate: new Date(2026, 11, 31, 23, 59) }); picker.on('submit', (date, readableDate) => { console.log(readableDate); });

Date Range Limits

Constrain selectable dates with minDate and maxDate. Out-of-range cells are visually disabled and ignore clicks.

Past dates and dates more than 30 days out are disabled...
const today = new Date(); const in30 = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 30); const picker = new EasyEpoch({ minDate: today, maxDate: in30, });

Seconds Precision

Set showSeconds: true to capture second-level precision in the time picker. Seconds appear in selectedDate and readableDate.

Click the button to pick a date with HH:MM:SS time...
const picker = new EasyEpoch({ showSeconds: true, }); picker.on('submit', (date, readableDate) => { console.log(date.getSeconds()); // preserved console.log(readableDate); // e.g. "1st June 2024 02:30:45 PM" });

Localization

Translate every visible string via the locale option. Anything you don't override falls back to English.

Pick a language, then open the picker...
const picker = new EasyEpoch({ locale: { months: ['Janvier', 'Février', 'Mars', /* ... */], days: ['Dimanche', 'Lundi', 'Mardi', /* ... */], daysShort: ['Dim', 'Lun', 'Mar', /* ... */], ok: 'Valider', cancel: 'Annuler', }, });

Linked Date Range Pickers

Wire two pickers together so the end date is always ≥ start date. EasyEpoch.linkRange() is sugar for linkAfter + linkBefore.

const start = new EasyEpoch('#start-container'); const end = new EasyEpoch('#end-container'); // end >= start, start <= end. Both bounds are inclusive (same-day allowed). EasyEpoch.linkRange(start, end); start.on('submit', (date, readableDate) => { document.querySelector('#start').value = readableDate; }); end.on('submit', (date, readableDate) => { document.querySelector('#end').value = readableDate; });

Runtime Range Updates

Use setMinDate() / setMaxDate() to change the picker's bounds at any time. Pass undefined to clear a bound.

Bounds: none. Click a button to constrain, then open to see the effect...
const picker = new EasyEpoch(); // Restrict to today onward picker.setMinDate(new Date()); // Clear it picker.setMinDate(undefined);

Event Handling

Listen to both submit and close events from the picker.

Event log appears here...
picker.on('submit', (date, readableDate) => { log.append(`Selected: ${readableDate}`); }); picker.on('close', () => { log.append('Picker was closed/cancelled'); });