HTMLDate & Time Inputs

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

date

A calendar date, no time or timezone

2026-07-11

time

A time of day, no date or timezone

14:30

datetime-local

A date and time, no timezone

2026-07-11T14:30

month

A specific year and month

2026-07

week

A specific year and ISO week number

2026-W28

date-time-basics.html

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

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">
step controls the picker's granularity
For 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 datetime-local and week before catching up — verify on your minimum supported browser version

Firefox and week/month

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 value is always the fixed format shown above

Always validate on the server too
Because unsupported browsers fall back to a free-text field, never trust that a submitted value matches the expected date/time format. Client-side pickers improve UX; server-side validation is what actually protects your data.
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

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 has no timezone — plan accordingly
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, or week to get a native picker UI with zero JavaScript.

  • min and max constrain 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

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

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 past
Combining 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

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

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

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

month

Card expiry, billing cycle, "month of birth" surveys

Anything needing a specific day

week

Sprint planning tools, weekly reports

Consumer-facing forms — most users don't think in ISO week numbers

Users rarely 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.