API Reference
Constructor
new Datepicker(
element: HTMLInputElement | string,
options?: DatepickerOptions
): Datepickerelement can be an HTMLInputElement or a CSS selector string.
Instance methods
Open / Close
| Method | Returns | Description |
|---|---|---|
open() | Promise<void> | Open the dropdown. Runs onBeforeOpen guard. |
close(reason?) | Promise<void> | Close the dropdown. Default reason: 'api'. |
toggle() | Promise<void> | Toggle open/closed. |
isOpen() | boolean | Whether the dropdown is currently open. |
Value
| Method | Returns | Description |
|---|---|---|
setValue(value, triggerChange?) | Promise<void> | Set value (string, Date, or null). Runs validation. |
getValue() | string | Current formatted value. |
getDate() | Date | null | Currently selected date (single mode). |
getDates() | Date[] | Selected dates (multiple mode). |
getRange() | DateRange | null | Selected range (range mode). DateRange = { from: Date, to: Date } |
setRange(from, to, triggerChange?) | Promise<void> | Set range programmatically (range mode). |
setDates(dates, triggerChange?) | Promise<void> | Set multiple dates (multiple mode). |
clear(triggerChange?) | Promise<void> | Clear all selections. |
setToday(triggerChange?) | Promise<void> | Select today's date. |
isValid() | Promise<boolean> | Validate current value. |
Programmatic changes and onChange
setValue, setRange, setDates, clear and setToday are silent by default: calling them from your own code does not fire onChange (or the vdp:change event). This mirrors how setting a native input.value from script never fires a change event, and matches flatpickr's setDate(date, triggerChange) convention — so inside onChange you never have to guess whether the update came from the user or from your own code, because your own code simply doesn't trigger it unless you ask it to.
Pass true as the last argument to opt in and notify listeners same as a user-driven change would:
// silent — onChange is NOT called
await dp.setValue('2026-09-01')
// explicit opt-in — onChange IS called, just like a user pick
await dp.setValue('2026-09-01', true)Selections made by the user (clicking a day, the Today button, typing + blur, the Clear button) always notify — this flag only affects calls you make from your own code.
Navigation
| Method | Returns | Description |
|---|---|---|
goToDate(date) | Promise<void> | Navigate calendar to the month of date. |
goToMonth(month, year) | Promise<void> | Navigate to given month (0-indexed) and year. |
goToNextMonth() | Promise<void> | Go to next month. |
goToPrevMonth() | Promise<void> | Go to previous month. |
goToNextYear() | Promise<void> | Go to next year (same month). |
goToPrevYear() | Promise<void> | Go to previous year (same month). |
switchView(view) | Promise<void> | Switch calendar view: 'days' | 'months' | 'years'. |
Configuration
| Method | Returns | Description |
|---|---|---|
setOptions(partial) | void | Merge new options at runtime. Re-renders an open calendar. See below. |
setLocale(locale) | void | Change locale (string or LocaleConfig). |
setTheme(theme) | void | Change theme ('light' | 'dark' | 'auto'). |
refresh() | Promise<void> | Re-render the open calendar. No-op when closed. |
focus() | void | Focus the input element. |
setOptions(partial) in detail
Options are merged into the live instance and take effect immediately:
- Callbacks are live. Every
onXoption is read at the moment the event fires, sosetOptions({ onClose })registers a callback that wasn't passed to the constructor, andsetOptions({ onClose: undefined })removes one that was. - An open calendar re-renders.
minDate,maxDate,disabledDates,disabledWeekdays,locale, footer buttons and the rest apply without closing the dropdown. The re-render does not fireonMonthChange— no month changed. minDate/maxDatere-validate the current value. If the value falls outside the new range,vdp:invalidfires withBELOW_MIN/ABOVE_MAXand the input gets thevdp-invalidclass. The value itself is kept — narrowing a range never silently wipes what the user entered. Clear it yourself if that's what you want.
A few options are consumed once during construction and cannot be changed this way: value, defaultValue, initialView, openOnFocus, allowManualInput.
// Keep the end picker's range in sync with the start picker.
dpStart.on('vdp:change', ({ date }) => dpEnd.setOptions({ minDate: date }))setLocale() and setTheme() are thin wrappers around setOptions() and behave identically.
Events
| Method | Returns | Description |
|---|---|---|
on(event, handler) | () => void | Subscribe to an event. Returns unsubscribe function. |
off(event, handler) | void | Unsubscribe from an event. |
Lifecycle
| Method | Returns | Description |
|---|---|---|
destroy() | void | Remove event listeners, clean up DOM, close dropdown. |
Static methods
| Method | Returns | Description |
|---|---|---|
Datepicker.getInstance(el) | Datepicker | null | Return the existing instance attached to el (element or CSS selector), or null if none. |
Datepicker.setDefaults(partial) | void | Set global defaults applied to all new instances. |
Datepicker.registerLocale(name, config) | void | Register a custom locale. |
Datepicker.autoInit(selector?) | Datepicker[] | Init all matching elements. Default: [data-datepicker]. |
Datepicker.parse(text, format?) | Date | null | Parse a date string. |
Datepicker.format(date, format?) | string | Format a date. |
Datepicker.getInstance
Retrieves the Datepicker instance previously created on a given input element. Returns null if the element has no associated instance (not yet initialised, or already destroyed).
Datepicker.getInstance(el: HTMLInputElement | string): Datepicker | nullUseful when you need to control a datepicker from code that doesn't hold a reference to the original instance — for example inside a framework component, an event handler, or a third-party plugin.
// by CSS selector
Datepicker.getInstance('#arrival')?.setValue('2026-09-01')
// by element reference
const input = document.querySelector<HTMLInputElement>('#arrival')!
Datepicker.getInstance(input)?.open()
// safe null-check
const dp = Datepicker.getInstance('#arrival')
if (dp) {
console.log(dp.getValue())
}The registry uses a WeakMap internally, so destroyed instances and detached elements are garbage-collected without any manual cleanup.
Keyboard & focus
When the calendar opens, no button or day cell receives focus — nothing is highlighted until the user actually starts navigating. Focus is parked on the dropdown element itself (.vdp-dropdown, role="dialog", tabindex="-1") so that keyboard events still reach the calendar.
From there:
| Key | Effect |
|---|---|
ArrowLeft / ArrowRight | First press moves focus onto the anchor cell (selected day → today → 1st of the displayed month). Every following press moves ±1 day. |
ArrowUp / ArrowDown | Same as above, ±1 week. |
PageUp / PageDown | ±1 month (with Shift: ±1 year). |
Enter / Space | Select the focused day, or activate the focused header/footer button. Selects nothing while no day is focused. |
Tab | Cycles through the focusable elements inside the dialog (focus trap). The anchor cell carries tabindex="0", so one Tab reaches the grid. |
Escape | Close the calendar. |
Arrow keys reach the grid from anywhere in the dialog, so navigation still works right after clicking a header arrow with the mouse. Focus also survives re-renders (month navigation, selection with closeOnSelect: false, range hover preview) — it returns to the same day cell, or to the dialog when that day is no longer displayed.
The month and year views still focus their selected cell when opened, because the user gets there by an explicit click on the header.
.vdp-dropdown sets outline: none, so parking focus on the dialog draws no ring. If you override dropdown styles, keep that rule (or the equivalent :focus-visible handling) to avoid a stray outline around the whole calendar.
keepFocus
With keepFocus: true the input gets focus back when a calendar that was holding focus closes (selection, Escape, close()), instead of dropping focus to <body>:
new Datepicker('#departure', { keepFocus: true })Focus is never stolen from somewhere else — if you close the calendar by clicking another field, that field keeps focus. Returning focus to the input does not reopen the calendar under openOnFocus: true; clicking the (already focused) input reopens it.
Format tokens
| Token | Output | Example |
|---|---|---|
YYYY | 4-digit year | 2026 |
YY | 2-digit year | 26 |
MM | 2-digit month | 07 |
M | Month (no pad) | 7 |
DD | 2-digit day | 04 |
D | Day (no pad) | 4 |
HH | 2-digit hour (24h) | 14 |
H | Hour (no pad) | 14 |
mm | 2-digit minutes | 05 |
m | Minutes (no pad) | 5 |
ss | 2-digit seconds | 09 |
s | Seconds (no pad) | 9 |