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.
- Features
- Installation
- Selection modes
- Dates, times, and restrictions
- Options reference
- Callbacks and form events
- Public methods
- Languages
- Keyboard and layout
- Local development
- Troubleshooting
- 📅 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.
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.
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.
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/bootstrap@5.3.8/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/jquery-extended-datetimepicker@1.5.3/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/jquery-extended-datetimepicker@1.5.3/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.
| 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 |
$("#my-datepicker").extendedDateTimePicker({
mode: "single",
lang: "en",
showClock: false,
selectedDates: ["2026-10-15"],
dateFormat: "DD/MM/YYYY",
});
// Input: 15/10/2026$("#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-picker").extendedDateTimePicker({
mode: "multiple",
showClock: false,
selectedDates: ["2026-10-15", "2026-10-20", "2026-10-23"],
});$("#birthday-picker").extendedDateTimePicker({
mode: "birthday",
lang: "en",
showClock: false,
selectedDates: ["2000-01-01"],
dateFormat: "DD/MM/YYYY",
});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.
- 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.
$("#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.
$("#time-picker").extendedDateTimePicker({
showCalendar: false,
showClock: true,
format24h: false,
defaultTime: "14:30",
});
// Input: 02:30 PM| 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. |
| 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.
$("#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.
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.
| 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.
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.
| 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. |
Created and maintained by Brayan Pineda Méndez / PinedaMB.
📄 Licensed under MIT. Contributions and reproducible bug reports are welcome through GitHub Issues.