jquery-extended-datetimepicker
v1.5.3
Published
A modern, modular jQuery DateTimePicker plugin with Bootstrap 5 integration, range selection, dual month view, and birthday mode.
Maintainers
Readme
🗓️ Extended DateTimePicker
A jQuery date and time picker styled with Bootstrap 5. Use it as an input dropdown or an always-visible inline control, with single dates, ranges, multiple dates, or birthdays.
🎮 Playground · 📦 npm · 💻 GitHub · 🐛 Report an issue · 📝 Changelog
See the changelog for the changes included in each version.
🧭 Contents
- Features
- Installation
- Selection modes
- Dates, times, and restrictions
- Options reference
- Callbacks and form events
- Public methods
- Languages
- Keyboard and layout
- Local development
- Troubleshooting
✨ Features
- 📅 Four selection modes: single date, range, multiple dates, and birthday.
- 🕒 Optional clock: 12-hour or 24-hour display, with separate start/end times for ranges.
- 🚫 Date restrictions: minimum/maximum dates, blocked dates, and disabled weekends.
- 📐 Responsive layouts: vertical or horizontal, with optional two-month calendars.
- 🌍 Spanish and English: built-in dictionaries, custom labels, and translated accessible controls.
- ⌨️ Form integration: keyboard navigation, selection callbacks, and native
input/changeevents.
📦 Installation
Requirements
The picker needs jQuery and Bootstrap CSS, plus its own JavaScript and CSS. Bootstrap JavaScript is not required by the picker itself.
The package declares jQuery >=3.0.0 and Bootstrap >=5.0.0 as peer dependencies. Use Bootstrap 5.3.8 for the theme utilities used by the current demo. A clean consumer installation was verified with jQuery 3.7.1 + Bootstrap 5.3.8.
With npm and a bundler
npm install jquery-extended-datetimepicker jquery bootstrapAdd a target to your page:
<label for="my-datepicker">Choose a date</label>
<input id="my-datepicker" type="text" class="form-control" />Import the plugin and both stylesheets in your JavaScript entry point:
import $ from "jquery";
import "bootstrap/dist/css/bootstrap.min.css";
import "jquery-extended-datetimepicker";
import "jquery-extended-datetimepicker/dist/jquery.extended.datetimepicker.min.css";
$(function () {
$("#my-datepicker").extendedDateTimePicker({
lang: "en",
showClock: false,
});
});The package entry is ESM. It imports jQuery from your project; there is no need to create a global $ for this setup.
With browser script tags / CDN
Load jQuery before the plugin. This example pins version 1.5.3; use the release you want to deploy.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Date picker example</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.extended.datetimepicker.min.css" />
</head>
<body>
<label for="my-datepicker">Choose a date</label>
<input id="my-datepicker" type="text" class="form-control" />
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.extended.datetimepicker.min.js"></script>
<script>
$("#my-datepicker").extendedDateTimePicker({ lang: "en", showClock: false });
</script>
</body>
</html>For self-hosted files, replace the plugin CDN URLs with paths to the files in dist/. Do not load the ESM file as a classic browser script.
🎛️ Selection modes
| Mode | Use it for | Initial selection |
| --- | --- | --- |
| single | One appointment or date | One ISO date |
| range | A start and end date | Up to two ISO dates |
| multiple | Separate dates | An array of ISO dates |
| birthday | Day, month, and year controls | One ISO date, year 1900 through the current year |
📅 Single date
$("#my-datepicker").extendedDateTimePicker({
mode: "single",
lang: "en",
showClock: false,
selectedDates: ["2026-10-15"],
dateFormat: "DD/MM/YYYY",
});
// Input: 15/10/2026↔️ Range with individual times
$("#range-picker").extendedDateTimePicker({
mode: "range",
lang: "en",
doubleMonth: true,
selectedDates: ["2026-10-15", "2026-10-20"],
defaultTime: ["09:00", "17:30"],
});
// Input: 2026-10-15 09:00 to 2026-10-20 17:30🗓️ Multiple dates
$("#multiple-picker").extendedDateTimePicker({
mode: "multiple",
showClock: false,
selectedDates: ["2026-10-15", "2026-10-20", "2026-10-23"],
});🎂 Birthday
$("#birthday-picker").extendedDateTimePicker({
mode: "birthday",
lang: "en",
showClock: false,
selectedDates: ["2000-01-01"],
dateFormat: "DD/MM/YYYY",
});📌 Inline control
Use a container instead of an input. The same configuration options apply:
<div id="inline-picker"></div>$("#inline-picker").extendedDateTimePicker({
showClock: false,
selectedDates: ["2026-10-15"],
});An input opens on focus or click. An inline container is visible immediately. Initialization replaces the contents of an inline container; destroying it does not restore those contents.
📅 Dates, times, and restrictions
Input values versus display format
- Always pass dates as
YYYY-MM-DDstrings, includingselectedDates,minDate,maxDate, anddisabledDates. Do not passDateobjects to these options. dateFormatchanges the displayed output, not the format of configuration values. Supported tokens areYYYY,YY,MM,M,DD, andD.- Pass
defaultTimein 24-hourHH:mmformat, even whenformat24hisfalse. A range accepts either one time for both ends or an array of two times. - Without
defaultTime, the clock starts at06:00for single/multiple/birthday modes, or00:00and23:59for a range. Invalid time strings use those defaults. - Date objects returned by callbacks represent local dates, not UTC timestamps.
Restrict selectable dates
$("#my-datepicker").extendedDateTimePicker({
minDate: "2026-10-01",
maxDate: "2026-10-31",
disableWeekends: true,
disabledDates: ["2026-10-12"],
showClock: false,
});Restrictions apply to initial selections, calendar clicks, birthdays, and Today. Invalid or blocked initial dates are ignored. For ranges, restrictions apply to the endpoints; blocked dates inside a selected range are permitted.
A blocked birthday edit clears the submitted input value until a valid date is selected again. Invalid date limits, reversed limits, unsupported modes, and malformed translations throw before replacing an existing picker.
Use only the clock
$("#time-picker").extendedDateTimePicker({
showCalendar: false,
showClock: true,
format24h: false,
defaultTime: "14:30",
});
// Input: 02:30 PM⚙️ Configurable Options Table
| Option | Type | Default | Description / Allowed Values |
| --- | --- | --- | --- |
| mode | string | 'single' | 'single', 'range', 'multiple', or 'birthday'. |
| layout | string | 'vertical' | 'vertical' or 'horizontal'. Horizontal applies when both calendar and clock are visible outside birthday mode. |
| showCalendar | boolean | true | Show the calendar; birthday mode uses its own date controls. |
| showClock | boolean | true | Show the clock. Set to false for date-only selection. |
| themeColor | string | 'success' | Bootstrap color name, such as 'primary', 'success', or 'danger'. |
| format24h | boolean | true | Use 24-hour display; false shows 12-hour time with AM/PM. |
| defaultTime | string/array/null | null | Initial HH:mm time, or two times for a range. Configuration always uses 24-hour format. |
| selectedDates | array | [] | Initial ISO dates. Single/birthday use one; range uses up to two; multiple accepts several. |
| minDate | string/null | null | Earliest selectable ISO date, inclusive. |
| maxDate | string/null | null | Latest selectable ISO date, inclusive. |
| disableWeekends | boolean | false | Disable Saturdays and Sundays. |
| disabledDates | array | [] | Specific ISO dates that cannot be selected. |
| doubleMonth | boolean | false | Display two consecutive calendar months. |
| dateFormat | string | 'YYYY-MM-DD' | Output format, for example 'DD/MM/YYYY'. |
| lang | string/object | 'es' | 'es', 'en', or a partial/custom translation object. |
| actions | array | ['close', 'today', 'now', 'clear'] | Footer buttons in the supplied order; [] hides them. Today requires the calendar; Now requires the clock; Close closes input dropdowns. |
🔄 Callbacks / Events
| Callback | Default | Parameters and behavior |
| --- | --- | --- |
| onOpen | No-op function | No arguments. Runs when a picker opens; this is the target element. |
| onClose | No-op function | No arguments. Runs when a picker closes, including when another input picker opens; this is the target element. |
| onSelectDate | null | (dateObj, formattedDates): a Date for single/birthday, an array of dates for range/multiple, and an array of formatted strings. Clear or a blocked birthday edit returns (null, []). Today also invokes this callback. |
| onSelectTime | null | (timeState): { hour, minute }, plus ampm in 12-hour mode. Range mode returns an array of start/end time objects. |
$("#my-datepicker").extendedDateTimePicker({
onSelectDate(date, formattedDates) {
console.log("Selected dates:", formattedDates);
},
onSelectTime(time) {
console.log("Selected time:", time);
},
});
$("#my-datepicker").on("change", function () {
console.log("Form value:", this.value);
});Form behavior:
- Initialization does not emit selection callbacks or
input/changeevents. - User edits emit
inputandchangewhen the input value changes. - An existing input value is preserved when no initial date selection is supplied, except in clock-only mode, which initializes the time. Existing text is not parsed into a selection.
- Clear empties the input and controls. Editing again restores the controls from their last valid state.
🛠️ Public methods
$("#my-datepicker").extendedDateTimePicker("open");
$("#my-datepicker").extendedDateTimePicker("close");
$("#my-datepicker").extendedDateTimePicker("destroy");Methods preserve jQuery chaining. Supported methods do nothing on uninitialized elements; unknown names throw an error.
Calling the plugin again with options replaces the current instance. destroy removes plugin controls/listeners and restores the input's original attributes. It does not restore content previously removed from an inline container.
🌍 Languages
Spanish is the default. Select English with lang: "en", or customize individual labels:
$("#my-datepicker").extendedDateTimePicker({
lang: {
actions: { clear: "Reset selection", close: "Close picker" },
},
});Partial custom dictionaries and unknown language codes fall back to Spanish. To customize English labels without Spanish fallbacks, start from the complete English dictionary:
import en from "jquery-extended-datetimepicker/langs/en.json";
en.actions.clear = "Reset selection";
$("#my-datepicker").extendedDateTimePicker({ lang: en });JSON imports require bundler support; direct Node.js JSON imports may require import attributes. Dictionary exports are available starting with version 1.5.3.
Custom dictionary rules:
calendar,clock,birthday, andactionsmust be objects when supplied.- Labels must be strings; translations are displayed as plain text, not HTML.
- Month arrays require 12 strings; weekday arrays require 7 strings.
- Calendar weekday labels use
calendar.weekdaysShort. - Accessible labels use
calendar.title,calendar.previous,calendar.next, andclock/birthdaykeysincreaseanddecrease. - Range clock headings use
clock.startandclock.end.
For contributors, src/js/modules/i18n.js is the single editable source. Run npm run langs:sync to regenerate langs/es.json and langs/en.json; do not edit the generated JSON files by hand. The build also regenerates them.
⌨️ Keyboard and layout
| Key | Action |
| --- | --- |
| Tab / Shift+Tab | Move between controls. |
| Arrow keys on calendar days | Move one day left/right or one week up/down within the rendered calendar, skipping disabled dates. |
| Enter / Space | Select a focused calendar day. |
| Escape | Close an input dropdown and return focus to its input. |
The horizontal layout switches to vertical when the component's available width is small. Two-month calendars can scroll horizontally in narrow containers. Clock buttons have larger targets on touch devices, and clock-only mode omits the date/clock separator.
The component uses Bootstrap CSS variables and CSS container queries. Keep the viewport meta tag in mobile pages and use browsers with container-query support.
🧑💻 Local development
Use npm; package-lock.json is the dependency lockfile. The current test dependencies require Node.js ^22.22.2, ^24.15.0, or >=26.0.0.
git clone https://github.com/PinedaMB/extended_datetimepicker.git
cd extended_datetimepicker
npm ci
npm run devOpen the local URL printed in the terminal (normally http://127.0.0.1:5173/). Changes to src/, docs/index.html, and docs/playground.css update the demo automatically. Stop the server with Ctrl+C.
The local demo uses source modules and local jQuery. Bootstrap is loaded from its CDN, so the playground still needs internet access for those assets. Development does not refresh dist/; run the build when you need distribution files.
| Command | Purpose |
| --- | --- |
| npm run dev | Start the local playground with automatic updates. |
| npm test | Run regression tests. |
| npm run build | Generate translation JSON, build ESM/browser bundles and CSS, copy assets to the demo, and synchronize its reference tables. |
| npm run langs:sync | Regenerate JSON dictionaries from the source translations. |
| npm run langs:check | Verify that generated dictionaries match the source. |
| npm run docs:sync | Update the playground's options/callbacks tables from this README. |
| npm run docs:check | Verify that those tables are synchronized. |
| npm audit | Check installed dependency advisories. |
| npm pack --dry-run | Inspect the package contents without publishing. |
Only the options and callbacks tables synchronize automatically from the README. Other playground documentation is maintained separately. The playground applies settings to both previews; applying with an empty initial-date field removes its previous preselection and input value.
Before preparing a release, run the build, tests, documentation/translation checks, and package inspection. Record changes under Unreleased in CHANGELOG.md, then assign the release version when publishing.
🩺 Troubleshooting
| Symptom | Check |
| --- | --- |
| extendedDateTimePicker is not a function | Load jQuery before the classic plugin script; with a bundler, import both from the same project. |
| The picker has no styling or the layout looks wrong | Include both Bootstrap CSS and the plugin CSS. |
| A configured date is missing | Use valid ISO strings and check limits, weekends, blocked dates, and birthday year bounds. |
| The output is in Spanish | Set lang: "en"; partial custom dictionaries fall back to Spanish. |
| Source edits do not appear in the published demo | npm run dev previews source; run npm run build to refresh distributable/demo assets before deployment. |
| Translation JSON checks fail after editing labels | Run npm run langs:sync and include the regenerated JSON files in the change. |
👤 Author and license
Created and maintained by Brayan Pineda Méndez / PinedaMB.
📄 Licensed under MIT. Contributions and reproducible bug reports are welcome through GitHub Issues.
