Date and Time Inputs
HTML5 added a family of input types for picking dates and times without any JavaScript: date, time, datetime-local, month, and week. Supporting browsers render a native picker UI — a calendar widget, a scrollable time wheel, and so on — tailored to the platform.
The Five Types
Type | Represents | Example value |
|---|---|---|
| A calendar date, no time or timezone | 2026-07-11 |
| A time of day, no date or timezone | 14:30 |
| A date and time, no timezone | 2026-07-11T14:30 |
| A specific year and month | 2026-07 |
| A specific year and ISO week number | 2026-W28 |
date-time-basics.html
<label for="birthday">Date of birth</label> <input type="date" id="birthday" name="birthday"> <label for="appt-time">Appointment time</label> <input type="time" id="appt-time" name="appt-time"> <label for="event">Event start</label> <input type="datetime-local" id="event" name="event"> <label for="billing-month">Billing month</label> <input type="month" id="billing-month" name="billing-month"> <label for="sprint">Sprint week</label> <input type="week" id="sprint" name="sprint">
Native Picker UX
On supporting browsers and devices, each type gets an appropriate built-in control: a mini calendar for date, a spinner or clock face for time, and combined controls for datetime-local. On mobile, these typically open a full-screen native picker matching the platform's design language — this consistency and familiarity is the main advantage over a custom JavaScript date picker.
Constraining the Range: min and max
All of these types accept min and max attributes, using the same format as the value itself, to restrict the selectable range. Combined with the Constraint Validation API, out-of-range values will fail native form validation.
min-max.html
<!-- Only allow booking dates in the next 90 days --> <label for="checkin">Check-in date</label> <input type="date" id="checkin" name="checkin" min="2026-07-11" max="2026-10-09"> <!-- Restrict appointment times to business hours --> <label for="slot">Appointment slot</label> <input type="time" id="slot" name="slot" min="09:00" max="17:00" step="1800">
time, step is in seconds (1800 = 30 minutes) and controls which increments the picker snaps to. Without it, most time pickers default to one-minute increments.Browser Support Caveats
Support for these input types is broad in modern browsers, but not perfectly uniform. A few gaps are worth knowing about before you rely on them:
Caveat | Detail |
|---|---|
Older Safari desktop | Historically had partial support for |
Firefox and | Support arrived later than Chrome/Edge — always check current caniuse data for your target audience |
Unsupported browser fallback | A browser with no support renders the input as a plain text field, accepting any typed string, not just valid dates |
Locale display | The picker's displayed format (e.g. MM/DD/YYYY vs DD/MM/YYYY) follows the user's OS/browser locale, but the underlying |
Fallback Pattern for Full Control
If you need a consistent picker experience across every browser (or need timezone support, which none of these native types provide), a common pattern is to detect support and swap in a JavaScript date-picker library only where the native input isn't available or isn't sufficient.
feature-detect.js
const input = document.createElement('input');
input.setAttribute('type', 'date');
const supportsDateInput = input.type === 'date';
if (!supportsDateInput) {
// Fall back to a JS-based date-picker library
// e.g. load and initialize a third-party widget here
}datetime-local deliberately omits timezone information. If your application needs to store an unambiguous instant in time (e.g. an event visible to users in different regions), capture the user's timezone separately and combine it with the local value on the server.Use
date,time,datetime-local,month, orweekto get a native picker UI with zero JavaScript.minandmaxconstrain the selectable range and integrate with native form validation.Unsupported browsers silently fall back to a plain text field — always validate the submitted value server-side.
None of these types carry timezone information — capture timezone separately if your app needs it.
Reading Values in JavaScript
Values from these inputs are always plain strings in the fixed formats shown earlier, regardless of the user's display locale. Convert them to a Date object when you need to do date arithmetic.
read-date-value.js
const input = document.getElementById('birthday');
input.addEventListener('change', () => {
console.log(input.value); // always "YYYY-MM-DD", e.g. "2026-07-11"
const parsed = new Date(input.value);
console.log(parsed.getFullYear()); // 2026
});Setting a Default to "Today"
There's no built-in HTML attribute for "default to today's date" — you set it with JavaScript at page load, formatting the current date to match the expected YYYY-MM-DD shape.
default-to-today.js
const dateInput = document.getElementById('checkin');
const today = new Date().toISOString().split('T')[0]; // "2026-07-11"
dateInput.value = today;
dateInput.min = today; // prevent selecting a date in the pastCombining date and time Inputs Instead of datetime-local
Because datetime-local's cross-browser picker UX has historically been inconsistent, some teams use two separate inputs — one date and one time — and combine their values in JavaScript before submission, trading a slightly more verbose UI for more predictable behavior.
separate-date-time.html
<label for="event-date">Event date</label> <input type="date" id="event-date" name="event-date"> <label for="event-time">Event time</label> <input type="time" id="event-time" name="event-time">
combine-values.js
const date = document.getElementById('event-date').value; // "2026-07-11"
const time = document.getElementById('event-time').value; // "14:30"
const combined = new Date(`${date}T${time}`);month and week: Less Common but Useful
month and week are less commonly used than date, but they're a good fit whenever the day-of-month or day-of-week genuinely doesn't matter — a billing cycle, a subscription renewal month, or a sprint identified by its ISO week number.
month-week-examples.html
<label for="expiry">Card expiry</label> <input type="month" id="expiry" name="expiry" min="2026-01"> <label for="report-week">Reporting week</label> <input type="week" id="report-week" name="report-week">
Type | Good fit | Poor fit |
|---|---|---|
| Card expiry, billing cycle, "month of birth" surveys | Anything needing a specific day |
| Sprint planning tools, weekly reports | Consumer-facing forms — most users don't think in ISO week numbers |
type="week" submits values like 2026-W28, which very few end users can map to a calendar date at a glance. It works well for internal tools where "week" is already the unit of planning, but is a poor choice for general consumer-facing date entry.