Vanilla JavaScript Date Picker Library


This date picker library helps you add calendar inputs, datetime fields, time selectors, and date ranges to any form without React, jQuery, or Flatpickr. Single date, range, time-only, and inline calendar modes, min/max limits, keyboard navigation, and a small instance API - all in a zero-dependency script that matches your other HCG libraries.

This page covers installation, live demos, options, API methods, React usage, and styling. Open the interactive demo page for every example in one place.

What is hcg-date-picker?

hcg-date-picker is a vanilla JavaScript date picker that attaches to text inputs. It opens a calendar popup (or renders inline), supports single dates, date ranges, multiple dates, month-only, year-only, datetime, time-only modes, and optional day labels via an events map, and syncs the formatted value back to the input. Call hcgDatePicker('#id', options) to create an instance.

Click the month and year title in the calendar header to switch to month view, then click again for a 12-year grid. Pick year, month, and day in sequence - about five clicks for a typical birth date.

hcg-date-picker examples: single date calendar, datetime with time controls, date range highlighting, and inline calendar
hcg-date-picker examples: single date calendar, datetime with time controls, date range highlighting, and inline calendar.

Why use hcg-date-picker?

Other libraries are popular but often add weight or extra dependencies. Native <input type="date"> looks different on every browser and lacks range or time styling. hcg-date-picker is a focused form control for plain HTML pages: one small script, sensible defaults, and no framework lock-in. See the feature list below for what it includes.

Live Demo

Click the input below to open a calendar. Click the month/year title to jump to month or year view - useful for birth dates and other far-past selections.

View the full demo page for datetime, range, time-only, min/max, inline, and API examples.

Features

Core capabilities of the library: modes, constraints, formats, locale, keyboard support, and the instance API.

  • Zero dependencies - one JS file and companion CSS.
  • Single, range, multiple, month, year, and time modes - one input for dates, ranges, multi-select, month/year pickers, or hours and minutes.
  • Range hover preview - after the start date, hovering days previews the in-range band.
  • Calendar events - show labels under day numbers (prices, holidays, and more).
  • Datetime - combine calendar and time selectors with enableTime.
  • Inline calendar - always-visible panel under the input.
  • Month and year views - click the header title to jump years quickly.
  • Min, max, disabled, and enabled dates - block out-of-range days, blacklist specific dates, or whitelist only allowed days.
  • Custom formats - dateFormat and timeFormat token patterns.
  • Locale overrides - weekday names, month names, Today, Clear, AM/PM, separators.
  • Keyboard - arrow keys, Enter, Escape when the popup is open.
  • Instance API - open(), setDate(), clear(), and more.
  • Static helpers - get(), destroy(), reset(), destroyAll().

Installation

Add the CSS and JavaScript via direct download, npm, or a CDN, then call hcgDatePicker() on your input.

Direct download

Approximate JavaScript sizes (CSS is separate). Prefer the minified file in production.

Build File Size
Formatted hcg-date-picker.js 70 KB
Minified hcg-date-picker.min.js 37 KB
HTML
<link rel="stylesheet" href="hcg-date-picker.css">
<script src="hcg-date-picker.js"></script>
npm

Install from npm:

Command line
npm install hcg-date-picker
JavaScript
import hcgDatePicker from "hcg-date-picker";
import "hcg-date-picker/hcg-date-picker.css";
CDN
HTML
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/hcg-date-picker@1/hcg-date-picker.css">
<script src="https://cdn.jsdelivr.net/npm/hcg-date-picker@1/hcg-date-picker.js"></script>

Basic Usage

After you install the files, call hcgDatePicker() on a host element. A text <input> is the usual choice for forms (the library syncs the formatted value into the field). You can also attach to a <button> (or other element) as a custom trigger and read the value from the instance API. The library adds the hcg-date-picker class and builds the calendar panel.

Attach to an input

Use <input type="text"> (not type="date"). Give it an id (or another selector you can target) and add readonly so users pick from the calendar instead of typing. Optionally set autocomplete="off" yourself if you want to suppress browser autofill. The formatted value is written to input.value on each change.

HTML
<input type="text" id="birthday" placeholder="Select a date" readonly>
JavaScript
const picker = hcgDatePicker('#birthday');
const formatted = picker.getFormattedDate();
Attach to a button

Any element can host the picker. On a <button>, click opens the panel and keyboard focus moves into the day grid so arrow keys work. The selection is not written into the button label. Use a separate preview element and update it from onChange, or read the value later with getFormattedDate() / getDate().

HTML
<button type="button" id="date-button">Pick a date</button>
<p id="date-button-preview">Selected: (none)</p>
JavaScript
const preview = document.getElementById('date-button-preview');

const picker = hcgDatePicker('#date-button', {
  onChange: (dates, formatted) => {
    preview.textContent = 'Selected: ' + (formatted || '(none)');
  },
});

// Or read later from the instance:
// picker.getFormattedDate();

Try the button trigger demo on the interactive demo page.

Try the basic usage demo on the interactive demo page.

Date and Time

Set enableTime: true to show hour and minute controls under the calendar. The input value includes both the date and the selected time. Read the result with getFormattedDate() (string) or getDate() (Date with time).

HTML
<input type="text" id="meeting-start" placeholder="Date and time" readonly>
JavaScript
const picker = hcgDatePicker('#meeting-start', {
  enableTime: true,
});

// Date object (includes hours and minutes)
const date = picker.getDate();

// Formatted string (dateFormat + timeFormat), e.g. "2026-07-01 14:30"
const formatted = picker.getFormattedDate();

Open the datetime picker demo on the interactive demo page.

Time Only

Use mode: 'time' when you only need hours and minutes. No calendar grid is shown. Set hour12: true for a 12-hour clock with AM/PM. Read the time with getFormattedDate() or take hours/minutes from getDate().

HTML
<input type="text" id="alarm" placeholder="Select a time" readonly>
JavaScript
const picker = hcgDatePicker('#alarm', {
  mode: 'time',
  hour12: true,
});

// Date object (use getHours / getMinutes for the selected time)
const date = picker.getDate();
const hours = date && date.getHours();
const minutes = date && date.getMinutes();

// Formatted string (timeFormat), e.g. "02:30 PM"
const formatted = picker.getFormattedDate();

See the time-only selector demo on the interactive demo page.

Month Only

Set mode: 'month' to pick a month and year without a day grid. The panel opens on the month view. Default format is Y-m (for example 2026-07). Click the year title to jump years, then choose a month. Use getFormattedDate() for Y-m, or read year/month from getDate().

HTML
<input type="text" id="billing-month" placeholder="Select a month" readonly>
JavaScript
const picker = hcgDatePicker('#billing-month', {
  mode: 'month',
});

// Date object (day is the 1st of the selected month)
const date = picker.getDate();
const year = date && date.getFullYear();
const month = date && (date.getMonth() + 1); // 1-12

// Formatted string (default dateFormat "Y-m"), e.g. "2026-07"
const formatted = picker.getFormattedDate();

Try the month-only picker demo on the interactive demo page.

Year Only

Set mode: 'year' to pick a year from a 12-year grid with no month or day selection. Default format is Y (for example 2026). Use the nav arrows to move between year ranges. Read the year with getFormattedDate() or getDate().getFullYear().

HTML
<input type="text" id="report-year" placeholder="Select a year" readonly>
JavaScript
const picker = hcgDatePicker('#report-year', {
  mode: 'year',
});

// Date object (1 January of the selected year)
const date = picker.getDate();
const year = date && date.getFullYear();

// Formatted string (default dateFormat "Y"), e.g. "2026"
const formatted = picker.getFormattedDate();

Open the year-only picker demo on the interactive demo page.

Date Range

Set mode: 'range' for a flight-style dual calendar: two months side by side. Click a start date, then an end date. After the start is chosen, hovering days previews the in-range band until you pick the end. Days between both ends highlight, and the input value formats as start to end. Use getDates() for both ends, or getFormattedDate() for the joined string.

HTML
<input type="text" id="trip-dates" placeholder="Start to end" readonly>
JavaScript
const picker = hcgDatePicker('#trip-dates', {
  mode: 'range',
});

// Date objects: [start, end] (length 0, 1, or 2)
const dates = picker.getDates();
const start = dates[0] || null;
const end = dates[1] || null;

// Formatted string, e.g. "2026-07-01 to 2026-07-15"
const formatted = picker.getFormattedDate();

Explore the date range demo on the interactive demo page.

Multiple Dates

Set mode: 'multiple' to toggle several dates on one input. Click a day to add it, click again to remove it. Selected values are joined with the locale multipleSeparator (default ', '). The popup stays open so you can keep picking. Use getDates() for the Date array, or getFormattedDate() for the joined string.

HTML
<input type="text" id="availability" placeholder="Select multiple dates" readonly>
JavaScript
const picker = hcgDatePicker('#availability', {
  mode: 'multiple',
});

// Date[] of every selected day
const dates = picker.getDates();

// Formatted string, e.g. "2026-07-01, 2026-07-08, 2026-07-15"
const formatted = picker.getFormattedDate();

Try the multiple dates demo on the interactive demo page.

Calendar Events

Pass an events map of Y-m-d keys to string labels to show text under day numbers - useful for ticket prices, holidays, or status notes. Labels are independent of selection and work in single, range, and multiple modes. Update them later with setOption('events', map).

HTML
<input type="text" id="flight-day" placeholder="Select a date" readonly>
JavaScript
hcgDatePicker('#flight-day', {
  events: {
    '2026-07-05': '$189',
    '2026-07-12': '$249',
    '2026-07-18': '$159',
    '2026-07-22': 'Sold out',
  },
});

Open the calendar events demo on the interactive demo page.

Min, Max, Disabled, and Enabled Dates

Limit selectable days with minDate and maxDate, block individual days with disabledDates, or allow only a whitelist with enabledDates. When enabledDates is a non-empty array, only those days can be chosen (still subject to min/max and disabledDates). Out-of-range and blocked days appear muted and cannot be chosen.

HTML
<input type="text" id="booking" placeholder="Within allowed range" readonly>
JavaScript
const today = new Date();
const minDate = new Date(today.getFullYear(), today.getMonth(), 1);
const maxDate = new Date(today.getFullYear(), today.getMonth() + 1, 0);

hcgDatePicker('#booking', {
  minDate: minDate,
  maxDate: maxDate,
  disabledDates: [
    new Date(today.getFullYear(), today.getMonth(), 15),
  ],
});

Test min and max date limits on the interactive demo page.

Inline Calendar

Set inline: true to keep the calendar always visible under the input instead of a popup. Useful for dashboards, booking layouts, and always-on date selection.

HTML
<input type="text" id="schedule" placeholder="Selected date" readonly>
JavaScript
hcgDatePicker('#schedule', {
  inline: true,
});

View the always-visible inline calendar on the interactive demo page.

Options Reference

Quick reference for all option types and defaults. See the Options copy-paste examples section below for copy-paste examples.

OptionTypeDefaultDescription
modestring'single'Picker mode: single, range, multiple, month, year, or time only.
enableTimebooleanfalseShow hour and minute controls under the calendar.
inlinebooleanfalseRender the calendar panel below the input instead of a popup.
dateFormatstring'Y-m-d'Output pattern for the date portion (see format tokens).
timeFormatstring'H:i'Output pattern for the time portion.
hour12booleanfalseUse 12-hour clock with AM/PM when formatting or picking time.
minDateDate | string | nullnullEarliest selectable calendar day.
maxDateDate | string | nullnullLatest selectable calendar day.
disabledDatesarray[]Specific dates that cannot be selected.
enabledDatesarray[]When non-empty, only these dates can be selected (whitelist).
eventsobject | nullnullMap of Y-m-d keys to labels shown under day numbers.
firstDayOfWeeknumber0Week start: 0=Sunday through 6=Saturday.
localeobject | nullnullOverride weekday names, month names, Today, Clear, AM, PM, rangeSeparator, and multipleSeparator.
closeOnSelectbooleantrueClose the popup after a complete selection (not inline).
openOnFocusbooleantrueOpen the popup when the input receives keyboard focus (click still opens).
showTodaybooleantrueShow the Today button in the panel footer.
showClearbooleantrueShow the Clear button in the panel footer.
appendToelement | string | nullnullParent for the popup panel (default: document.body).
disabledbooleanfalseDisable the input and block opening the panel.
themestring'light'Panel theme: 'light' or 'dark' (sets CSS variables via .hcg-date-picker-panel-dark).
onChangefunction | nullnullCalled when the selection changes.
onOpenfunction | nullnullCalled when the popup opens.
onClosefunction | nullnullCalled when the popup closes.

Options

Copy-paste examples for each option. See Options reference types and defaults table above for types and default values.

mode

Choose how users pick a value: one day, a start/end range, several dates, month, year, or time only. Supported: single, range, multiple, month, year, time. Default: 'single'.

JavaScript
hcgDatePicker('#event-date', {
  mode: 'single', // single, range, multiple, month, year, time
});

Demo Mode

enableTime

Add hour and minute controls under the day grid for datetime fields. Supported: true, false. Default: false.

JavaScript
hcgDatePicker('#meeting', {
  enableTime: true, // true, false
});

Demo Enable time

inline

Keep the calendar always visible under the input instead of a popup. Supported: true, false. Default: false.

JavaScript
hcgDatePicker('#inline-date', {
  inline: true, // true, false
});

Demo Inline

dateFormat

Control how the date portion is written into the input. Supported tokens include Y, y, m, n, d, j, F, M. Default: 'Y-m-d'.

JavaScript
hcgDatePicker('#us-date', {
  dateFormat: 'Y-m-d', // Y-m-d, m/d/Y, d.m.Y, F j, Y
});
timeFormat

Control how the time portion is formatted when time picking is on. Supported tokens include H, G, h, g, i, s, A, a. Default: 'H:i'.

JavaScript
hcgDatePicker('#time', {
  mode: 'time',
  timeFormat: 'H:i', // H:i, H:i:s, h:i A
});

Demo Time format

hour12

Switch the time UI and formatting between 24-hour and 12-hour with AM/PM. Supported: true, false. Default: false.

JavaScript
hcgDatePicker('#time', {
  mode: 'time',
  hour12: true, // true, false
});

Demo 12-hour clock

minDate

Block days before a booking window or today. Supported: Date, structured string ('Y-m-d'), null. Default: null.

JavaScript
hcgDatePicker('#start', {
  minDate: new Date(), // Date, '2026-07-01', null
});

Demo Min date

maxDate

Block days after a deadline or season end. Supported: Date, structured string ('Y-m-d'), null. Default: null.

JavaScript
hcgDatePicker('#end', {
  maxDate: '2026-12-31', // Date, '2026-12-31', null
});

Demo Max date

disabledDates

Block specific holidays or closed days without changing the whole range. Supported array items: Date, structured string ('Y-m-d'). Default: [].

JavaScript
hcgDatePicker('#holiday', {
  disabledDates: ['2026-12-25', '2026-01-01'], // Date, 'Y-m-d'
});

Demo Disabled dates

enabledDates

Whitelist only the days users may pick. When the array is non-empty, every other day is disabled. Still respects minDate, maxDate, and disabledDates. Supported array items: Date, structured string ('Y-m-d'). Default: [].

JavaScript
hcgDatePicker('#slots', {
  enabledDates: ['2026-07-05', '2026-07-12', '2026-07-19'], // Date, 'Y-m-d'
});

Demo Enabled dates

events

Show labels under day numbers (ticket prices, holidays, status). Keys must be Y-m-d strings; values are display text. Default: null.

JavaScript
hcgDatePicker('#flight-day', {
  events: {
    '2026-07-05': '$189',
    '2026-07-12': '$249',
  },
});

Demo Calendar events

firstDayOfWeek

Set which weekday starts each row (Sunday vs Monday calendars). Supported: 0 (Sunday) through 6 (Saturday). Default: 0.

JavaScript
hcgDatePicker('#eu-week', {
  firstDayOfWeek: 1, // 0-6 (0 = Sunday)
});

Demo First day of week

locale

Override calendar labels for another language. Supported keys: weekdays, months, today, clear, am, pm, rangeSeparator, multipleSeparator. Default: null.

HTML
<input type="text" id="localized" placeholder="Start to end" dir="rtl" readonly>
JavaScript
hcgDatePicker('#localized', {
  mode: 'range',
  locale: { // weekdays, months, today, clear, am, pm, rangeSeparator, multipleSeparator
    today: 'اليوم',
    clear: 'مسح',
    rangeSeparator: ' إلى ',
    weekdays: ['أحد', 'إثن', 'ثلا', 'أرب', 'خمي', 'جمع', 'سبت'],
    months: [
      'يناير', 'فبراير', 'مارس', 'أبريل', 'مايو', 'يونيو',
      'يوليو', 'أغسطس', 'سبتمبر', 'أكتوبر', 'نوفمبر', 'ديسمبر',
    ],
  },
});

Demo Locale

closeOnSelect

Close the popup automatically after a complete pick, or keep it open for more edits. Supported: true, false. Default: true.

JavaScript
hcgDatePicker('#stay-open', {
  closeOnSelect: false, // true, false
});
openOnFocus

Open the popup on keyboard focus as well as click. Set false if focus alone should leave the calendar closed. Supported: true, false. Default: true.

JavaScript
hcgDatePicker('#click-only', {
  openOnFocus: false, // true, false
});
showToday

Show or hide the Today footer button. Supported: true, false. Default: true.

JavaScript
hcgDatePicker('#no-today', {
  showToday: false, // true, false
});
showClear

Show or hide the Clear footer button. Supported: true, false. Default: true.

JavaScript
hcgDatePicker('#no-clear', {
  showClear: false, // true, false
});
appendTo

Mount the popup panel under a specific container instead of document.body (useful inside modals or overflow parents). Supported: element, CSS selector, null. Default: null.

HTML
<input type="text" id="modal-date" placeholder="Select a date" readonly>

<div id="modal-root">
  <!-- Date picker panel is appended here when appendTo: '#modal-root' (keeps the calendar inside the modal) -->
</div>
JavaScript
hcgDatePicker('#modal-date', {
  appendTo: '#modal-root', // element, selector, null
});
disabled

Lock the field so users cannot open or change the value. Supported: true, false. Default: false.

JavaScript
hcgDatePicker('#locked', {
  disabled: true, // true, false
});
theme

Switch the panel between light and dark palettes. Uses CSS variables on .hcg-date-picker-panel. Supported: 'light', 'dark'. Default: 'light'.

JavaScript
hcgDatePicker('#dark-date', {
  theme: 'dark', // 'light', 'dark'
  inline: true,
});

Try the dark theme demo

onChange

React when the selection updates (sync UI, validate, or log). Callback args: dates, formatted, instance. Default: null.

JavaScript
hcgDatePicker('#sync', {
  onChange: (dates, formatted, instance) => { // dates, formatted, instance
    console.log(formatted, instance.getDate());
  },
});
onOpen

Run logic when the popup opens (analytics, focus traps, etc.). Callback args: instance. Default: null.

JavaScript
hcgDatePicker('#audit', {
  onOpen: (instance) => { // instance
    console.log('opened');
  },
});
onClose

Run logic when the popup closes (cleanup or final validation). Callback args: instance. Default: null.

JavaScript
hcgDatePicker('#audit', {
  onClose: (instance) => { // instance
    console.log('closed');
  },
});

API Reference

hcgDatePicker(selector, options) returns an instance with these methods. The factory also exposes hcgDatePicker.version, get(), destroy(), reset(), and destroyAll().

Method / PropertyReturnsDescription
open()instanceShow the calendar popup and position it under the input.
close()instanceHide the popup panel.
toggle()instanceOpen if closed, close if open.
getDate()Date | nullSelected date for single or datetime mode.
getFormattedDate()stringSelected value formatted with dateFormat / timeFormat (from internal state, not input.value).
setDate(value, triggerChange?)instanceSet one date. Second argument defaults to true for onChange.
getDates()Date[]All selected dates (range or multiple mode).
setDates(values, triggerChange?)instanceSet one or more dates (range or multiple mode).
clear()instanceClear the selection and input value.
gotoDate(value)instanceMove the calendar view to a month without changing selection.
setOption(key, value)instanceUpdate any option at runtime.
getOption(key)anyRead a current option value.
enable()instanceRe-enable the picker.
disable()instanceDisable the picker and close the popup.
reset()instanceRe-parse the input value and refresh the view.
destroy()voidRemove listeners, panel DOM, and the instance reference.
Method / PropertyReturnsDescription
hcgDatePicker.get(target)instance | nullStatic helper to retrieve an instance.
hcgDatePicker.destroy(target)booleanStatic helper to destroy an instance.
hcgDatePicker.reset(target)booleanStatic helper to reset an instance.
hcgDatePicker.destroyAll()voidDestroy every active instance on the page.
hcgDatePicker.versionstringLibrary version string (currently '1.0.0').
open() / close() / toggle()

Open, close, or toggle the popup panel programmatically.

JavaScript
picker.open();
picker.close();
picker.toggle();
getDate() / setDate(value, triggerChange?)

Read or set the selected date. setDate accepts a Date, timestamp, or structured string ('Y-m-d', optional time). Pass false as the second argument to skip onChange.

JavaScript
const date = picker.getDate();
picker.setDate(new Date());
picker.setDate('2026-07-29', false);
getFormattedDate()

Return the selected value as a string using dateFormat / timeFormat. Built from the internal selection, not from input.value, so console edits to the field do not affect the result. Empty selection returns ''. In range mode, both ends are joined with the locale range separator. In multiple mode, dates are joined with multipleSeparator.

JavaScript
const picker = hcgDatePicker('#birthday', { dateFormat: 'Y-m-d' });
picker.setDate('2026-07-01');

picker.getDate();          // Date object
picker.getFormattedDate(); // "2026-07-01"
getDates() / setDates(values, triggerChange?)

Read or set multiple dates for range or multiple mode. setDates accepts an array of values.

JavaScript
const dates = picker.getDates();
picker.setDates(['2026-07-01', '2026-07-15']);
clear() / gotoDate(value)

clear() empties the selection. gotoDate() moves the calendar view without changing the selected value.

JavaScript
picker.clear();
picker.gotoDate('1990-06-15');
setOption(key, value) / getOption(key)

Update or read any option at runtime. Changing layout options re-renders the panel.

JavaScript
picker.setOption("minDate", new Date());
picker.setOption("hour12", true);
const mode = picker.getOption("mode");
enable() / disable()

Toggle whether the input and panel can be used. disable() also closes the popup.

JavaScript
picker.disable();
picker.enable();
reset()

Re-parse the current input value and refresh the calendar view.

JavaScript
picker.reset();

// Without storing the instance:
hcgDatePicker.reset('#birthday');
destroy()

Remove event listeners, the panel DOM node, ARIA attributes, and the instance reference on the input.

JavaScript
picker.destroy();

// Without storing the instance:
hcgDatePicker.destroy('#birthday');
Static: get(), destroy(), reset(), destroyAll(), version

Factory-level helpers and the version string exposed on hcgDatePicker.version.

JavaScript
const picker = hcgDatePicker.get("#birthday");
hcgDatePicker.destroy("#birthday");
hcgDatePicker.reset("#birthday");
hcgDatePicker.destroyAll();
console.log(hcgDatePicker.version); // "1.0.0"

Callbacks

The library reports value and panel changes through onChange, onOpen, and onClose. Pass them when you create the instance, or update later with setOption().

onChange

Fires when the selection changes (day click, time change, Today, Clear, or programmatic setDate() / setDates()). Receives (dates, formatted, instance) where dates is an array of Date objects and formatted is the display string written to the input.

JavaScript
const status = document.querySelector('#date-status');

hcgDatePicker('#event-date', {
  onChange: (dates, formatted, instance) => {
    status.textContent = formatted || '(none)';
    console.log('Selected:', dates, instance.getDate());
  },
});
onOpen

Fires when the popup opens (focus, click, or open()). Receives (instance).

JavaScript
hcgDatePicker('#event-date', {
  onOpen: (instance) => {
    console.log('Picker opened', instance);
  },
});
onClose

Fires when the popup closes (outside click, Escape, selection, or close()). Receives (instance).

JavaScript
hcgDatePicker('#event-date', {
  onClose: (instance) => {
    console.log('Picker closed', instance);
  },
});
Change callbacks at runtime

Replace any callback option after init with setOption().

JavaScript
const picker = hcgDatePicker('#event-date');

picker.setOption('onChange', (dates, formatted) => {
  console.log('New handler:', formatted);
});

Using with React

Create the picker in useEffect and call destroy() on unmount. Keep the input in JSX.

Open the React date picker demo on StackBlitz

JavaScript
import { useEffect, useRef } from "react";
import hcgDatePicker from "hcg-date-picker";
import "hcg-date-picker/hcg-date-picker.css";

export const EventDateField = () => {
  const inputRef = useRef(null);

  useEffect(() => {
    const picker = hcgDatePicker(inputRef.current, { enableTime: true });
    return () => picker.destroy();
  }, []);

  return (
    <input ref={inputRef} type="text" placeholder="Select date and time" readOnly />
  );
};

Styling and Customization

Colors, borders, and accents use CSS variables on .hcg-date-picker-panel. Override them for a custom light or dark look, or set theme: 'dark' for the built-in dark preset.

CSS
/* Custom light accents */
.hcg-date-picker-panel {
  --hcg-dp-accent: #0f766e;
  --hcg-dp-accent-hover: #0d9488;
  --hcg-dp-hover-bg: #ccfbf1;
  --hcg-dp-hover-text: #115e59;
}

/* Or redefine the dark preset values */
.hcg-date-picker-panel-dark {
  --hcg-dp-bg: #0b1220;
  --hcg-dp-border: #1e293b;
  --hcg-dp-text: #e2e8f0;
  --hcg-dp-accent: #38bdf8;
  --hcg-dp-accent-hover: #7dd3fc;
}
JavaScript
hcgDatePicker('#dark-date', {
  theme: 'dark',
});

/* Toggle at runtime */
picker.setOption('theme', 'light');

Browser Support

Modern browsers with CSS flexbox and Pointer Events. IE11 is not supported.

  • Chrome, Edge, Firefox, Safari (current versions)
  • iOS Safari and Chrome for Android

FAQ

Common questions about dependencies, date modes, events, limits, dark theme, and CDN setup.

Does hcg-date-picker have any dependencies?

No. hcg-date-picker is plain vanilla JavaScript with zero dependencies. Include hcg-date-picker.js and hcg-date-picker.css and you are ready to go.

Can I pick a date range with one input?

Yes. Set mode to range on a single text input. The popup shows two months side by side like a flight booking calendar. After you pick the start date, hovering days previews the in-range band. The library formats the value as start to end and highlights days between both ends.

Can I select multiple dates?

Yes. Set mode to multiple to toggle several dates on one input. Click a selected day again to remove it. Values are joined with the locale multipleSeparator (comma by default).

How do I show prices or labels under calendar days?

Pass an events object mapping Y-m-d date keys to string labels. Each matching day shows the label under the day number, similar to ticket prices on a booking calendar.

How do I select a birth year quickly?

Click the month and year title in the calendar header to open the month grid, click the year title again for a 12-year range, pick a year, then a month, then the day. Birth dates typically take about five clicks.

Does it support time only inputs?

Yes. Set mode to time for hour and minute selectors without a calendar. Combine enableTime: true with mode single for datetime pickers.

Can I pick month only or year only?

Yes. Set mode to month for a month and year picker (default format Y-m). Set mode to year for a year-only grid (default format Y). Neither mode shows the day calendar.

Can I set min and max dates?

Yes. Pass minDate and maxDate as Date objects or structured strings such as Y-m-d. Use disabledDates for specific blocked days, or enabledDates for a whitelist of only allowed days.

Does it support a dark theme?

Yes. Set theme: 'dark' for the built-in dark palette (class hcg-date-picker-panel-dark). Override the --hcg-dp-* CSS variables for custom light or dark colors, or call setOption('theme', 'light') to switch at runtime.

Can I load hcg-date-picker from a CDN?

Yes. Add link and script tags for hcg-date-picker.css and hcg-date-picker.js from jsDelivr, unpkg, or your own hosted copy, then call hcgDatePicker("#input", options).