Browse Components
Date Picker
Choose a date with a clear calendar or familiar native input.
Basic
Enter a date directly, or open the calendar. The browser’s own input remains available without JavaScript.
Choose a date or enter it directly. This example does not save it.
View Code
<div class="field">
<label for="start-date">
Start date
</label>
<div class="datepicker" data-datepicker>
<input
class="input"
type="date"
id="start-date"
name="start"
aria-describedby="date-help"
>
<button type="button" data-datepicker-open aria-label="Choose a date" hidden>
<svg
class="icon"
aria-hidden="true"
focusable="false"
xmlns="http://www.w3.org/2000/svg"
viewbox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.75"
stroke-linecap="round"
stroke-linejoin="round"
>
<rect x="3" y="5" width="18" height="16" rx="2">
</rect>
<path d="M7 3v4m10-4v4M3 10h18M7 14h2m4 0h2m-8 3h2">
</path>
</svg>
</button>
</div>
<p class="muted" id="date-help">
Choose a date or enter it directly. This example does not save it.
</p>
</div>Date range
Choose a start and end date. Use one calendar: choose the start, then the end, across any months or years. Same-day ranges are allowed; dates before the chosen start stay unavailable for the end. The range appears in one field. Without JavaScript, use the separate start and end inputs.
View Code
<fieldset class="stack" data-date-range>
<legend>
Date range
</legend>
<div class="datepicker-fields">
<div class="field">
<label for="start-date">
Start date
</label>
<div class="datepicker" data-datepicker>
<input
class="input"
type="date"
data-range-start
value="2026-11-10"
id="start-date"
name="start"
aria-describedby="date-help"
>
<button type="button" data-datepicker-open aria-label="Choose a date" hidden>
<svg
class="icon"
aria-hidden="true"
focusable="false"
xmlns="http://www.w3.org/2000/svg"
viewbox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.75"
stroke-linecap="round"
stroke-linejoin="round"
>
<rect x="3" y="5" width="18" height="16" rx="2">
</rect>
<path d="M7 3v4m10-4v4M3 10h18M7 14h2m4 0h2m-8 3h2">
</path>
</svg>
</button>
</div>
<p class="muted" id="date-help">
Choose a start date in any month or year.
</p>
</div>
<div class="field">
<label for="end-date">
End date
</label>
<div class="datepicker" data-datepicker>
<input
class="input"
type="date"
data-range-end
value="2026-11-15"
id="end-date"
name="end"
aria-describedby="end-help range-error"
>
<button type="button" data-datepicker-open aria-label="Choose a date" hidden>
<svg
class="icon"
aria-hidden="true"
focusable="false"
xmlns="http://www.w3.org/2000/svg"
viewbox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.75"
stroke-linecap="round"
stroke-linejoin="round"
>
<rect x="3" y="5" width="18" height="16" rx="2">
</rect>
<path d="M7 3v4m10-4v4M3 10h18M7 14h2m4 0h2m-8 3h2">
</path>
</svg>
</button>
</div>
<p class="muted" id="end-help">
Choose an end date on or after the start date.
</p>
</div>
</div>
<p id="range-error" data-range-error aria-live="polite">
</p>
</fieldset>Date and time
Pair the calendar with a time field. Both have separate labels and values; your application supplies the scheduling time zone.
Choose a date or enter it directly. This example does not save it.
Local time. Nothing is saved in this example.
View Code
<div class="datepicker-fields">
<div class="field">
<label for="start-date">
Start date
</label>
<div class="datepicker" data-datepicker>
<input
class="input"
type="date"
id="start-date"
name="start"
aria-describedby="date-help"
>
<button type="button" data-datepicker-open aria-label="Choose a date" hidden>
<svg
class="icon"
aria-hidden="true"
focusable="false"
xmlns="http://www.w3.org/2000/svg"
viewbox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.75"
stroke-linecap="round"
stroke-linejoin="round"
>
<rect x="3" y="5" width="18" height="16" rx="2">
</rect>
<path d="M7 3v4m10-4v4M3 10h18M7 14h2m4 0h2m-8 3h2">
</path>
</svg>
</button>
</div>
<p class="muted" id="date-help">
Choose a date or enter it directly. This example does not save it.
</p>
</div>
<div class="field">
<label for="start-time">
Time
</label>
<div class="datepicker" data-timepicker data-hour-format="12">
<input
class="input"
type="time"
id="start-time"
name="time"
value="09:00"
step="60"
aria-describedby="time-help"
>
<button type="button" aria-label="Choose a time" hidden>
<svg
class="icon"
aria-hidden="true"
focusable="false"
xmlns="http://www.w3.org/2000/svg"
viewbox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.75"
stroke-linecap="round"
stroke-linejoin="round"
>
<circle cx="12" cy="12" r="9">
</circle>
<path d="M12 7v5l3 2">
</path>
</svg>
</button>
</div>
<p class="muted" id="time-help">
Local time. Nothing is saved in this example.
</p>
</div>
</div>24-hour time
The default picker uses 24-hour time. The field and picker both show 17:00. Native entry remains available without JavaScript.
Local time. Nothing is saved in this example.
View Code
<div class="field">
<label for="start-time">
Time
</label>
<div class="datepicker" data-timepicker>
<input
class="input"
type="time"
id="start-time"
name="time"
value="17:00"
step="60"
aria-describedby="time-help"
>
<button type="button" aria-label="Choose a time" hidden>
<svg
class="icon"
aria-hidden="true"
focusable="false"
xmlns="http://www.w3.org/2000/svg"
viewbox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.75"
stroke-linecap="round"
stroke-linejoin="round"
>
<circle cx="12" cy="12" r="9">
</circle>
<path d="M12 7v5l3 2">
</path>
</svg>
</button>
</div>
<p class="muted" id="time-help">
Local time. Nothing is saved in this example.
</p>
</div>With seconds and limits
Use step="1" for second precision. Native constraints support validation; validate submitted values on the server too.
Choose a time between 09:00:00 and 17:00:00.
View Code
<div class="field">
<label for="start-time">
Time
</label>
<div class="datepicker" data-timepicker data-hour-format="12">
<input
class="input"
type="time"
id="start-time"
name="time"
value="09:30:00"
min="09:00:00"
max="17:00:00"
step="1"
aria-describedby="time-help"
>
<button type="button" aria-label="Choose a time" hidden>
<svg
class="icon"
aria-hidden="true"
focusable="false"
xmlns="http://www.w3.org/2000/svg"
viewbox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.75"
stroke-linecap="round"
stroke-linejoin="round"
>
<circle cx="12" cy="12" r="9">
</circle>
<path d="M12 7v5l3 2">
</path>
</svg>
</button>
</div>
<p class="muted" id="time-help">
Choose a time between 09:00:00 and 17:00:00.
</p>
</div>Date limits
This example accepts November 5–25, 2026. Unavailable days remain discoverable, but cannot be selected.
Choose a date from November 5 through November 25, 2026.
View Code
<div class="field">
<label for="start-date">
Start date
</label>
<div class="datepicker" data-datepicker>
<input
class="input"
type="date"
min="2026-11-05"
max="2026-11-25"
value="2026-11-15"
id="start-date"
name="start"
aria-describedby="date-help"
>
<button type="button" data-datepicker-open aria-label="Choose a date" hidden>
<svg
class="icon"
aria-hidden="true"
focusable="false"
xmlns="http://www.w3.org/2000/svg"
viewbox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.75"
stroke-linecap="round"
stroke-linejoin="round"
>
<rect x="3" y="5" width="18" height="16" rx="2">
</rect>
<path d="M7 3v4m10-4v4M3 10h18M7 14h2m4 0h2m-8 3h2">
</path>
</svg>
</button>
</div>
<p class="muted" id="date-help">
Choose a date from November 5 through November 25, 2026.
</p>
</div>Required and invalid
A static validation example. Your application clears the error after correction and validates again on the server.
Error: choose a start date before continuing.
View Code
<div class="field">
<label for="start-date">
Start date (required)
</label>
<div class="datepicker" data-datepicker>
<input
class="input"
type="date"
required
aria-invalid="true"
id="start-date"
name="start"
aria-describedby="date-help"
>
<button type="button" data-datepicker-open aria-label="Choose a date" hidden>
<svg
class="icon"
aria-hidden="true"
focusable="false"
xmlns="http://www.w3.org/2000/svg"
viewbox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.75"
stroke-linecap="round"
stroke-linejoin="round"
>
<rect x="3" y="5" width="18" height="16" rx="2">
</rect>
<path d="M7 3v4m10-4v4M3 10h18M7 14h2m4 0h2m-8 3h2">
</path>
</svg>
</button>
</div>
<p class="field-error" id="date-help">
Error: choose a start date before continuing.
</p>
</div>Disabled and read-only
Disabled fields are omitted from submission. Read-only dates remain included in submission; neither opens the custom calendar.
Choose a project before setting its start date.
This approved date cannot be edited.
View Code
<div class="field">
<label for="start-date">
Start date
</label>
<div class="datepicker" data-datepicker>
<input
class="input"
type="date"
disabled
id="start-date"
name="start"
aria-describedby="date-help"
>
<button type="button" data-datepicker-open aria-label="Choose a date" hidden>
<svg
class="icon"
aria-hidden="true"
focusable="false"
xmlns="http://www.w3.org/2000/svg"
viewbox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.75"
stroke-linecap="round"
stroke-linejoin="round"
>
<rect x="3" y="5" width="18" height="16" rx="2">
</rect>
<path d="M7 3v4m10-4v4M3 10h18M7 14h2m4 0h2m-8 3h2">
</path>
</svg>
</button>
</div>
<p class="muted" id="date-help">
Choose a project before setting its start date.
</p>
</div>
<div class="field">
<label for="approved-date">
Approved date
</label>
<div class="datepicker" data-datepicker>
<input
class="input"
type="date"
readonly
value="2026-11-15"
id="approved-date"
name="approved"
aria-describedby="approved-help"
>
<button type="button" data-datepicker-open aria-label="Choose a date" hidden>
<svg
class="icon"
aria-hidden="true"
focusable="false"
xmlns="http://www.w3.org/2000/svg"
viewbox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.75"
stroke-linecap="round"
stroke-linejoin="round"
>
<rect x="3" y="5" width="18" height="16" rx="2">
</rect>
<path d="M7 3v4m10-4v4M3 10h18M7 14h2m4 0h2m-8 3h2">
</path>
</svg>
</button>
</div>
<p class="muted" id="approved-help">
This approved date cannot be edited.
</p>
</div>Right-to-left
Date names use the content language. Translate control labels separately; this example also starts weeks on Monday.
בחרו תאריך או הזינו אותו ישירות. התאריך אינו נשמר.
View Code
<div dir="rtl" lang="he">
<div class="field">
<label for="start-date">
תאריך התחלה
</label>
<div
class="datepicker"
data-datepicker
data-week-start="1"
data-title="בחירת תאריך"
data-previous-month="החודש הקודם"
data-next-month="החודש הבא"
data-previous-year="השנה הקודמת"
data-next-year="השנה הבאה"
data-previous-years="השנים הקודמות"
data-next-years="השנים הבאות"
data-month="חודש"
data-year="שנה"
>
<input
class="input"
type="date"
id="start-date"
name="start"
aria-describedby="date-help"
>
<button type="button" data-datepicker-open aria-label="בחירת תאריך" hidden>
<svg
class="icon"
aria-hidden="true"
focusable="false"
xmlns="http://www.w3.org/2000/svg"
viewbox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.75"
stroke-linecap="round"
stroke-linejoin="round"
>
<rect x="3" y="5" width="18" height="16" rx="2">
</rect>
<path d="M7 3v4m10-4v4M3 10h18M7 14h2m4 0h2m-8 3h2">
</path>
</svg>
</button>
</div>
<p class="muted" id="date-help">
בחרו תאריך או הזינו אותו ישירות. התאריך אינו נשמר.
</p>
</div>
</div>Without motion
The calendar opens immediately when reduced motion is preferred or data-motion is none.
Choose a date or enter it directly. This example does not save it.
View Code
<div data-motion="none">
<div class="field">
<label for="start-date">
Start date
</label>
<div class="datepicker" data-datepicker>
<input
class="input"
type="date"
id="start-date"
name="start"
aria-describedby="date-help"
>
<button type="button" data-datepicker-open aria-label="Choose a date" hidden>
<svg
class="icon"
aria-hidden="true"
focusable="false"
xmlns="http://www.w3.org/2000/svg"
viewbox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.75"
stroke-linecap="round"
stroke-linejoin="round"
>
<rect x="3" y="5" width="18" height="16" rx="2">
</rect>
<path d="M7 3v4m10-4v4M3 10h18M7 14h2m4 0h2m-8 3h2">
</path>
</svg>
</button>
</div>
<p class="muted" id="date-help">
Choose a date or enter it directly. This example does not save it.
</p>
</div>
</div>Installation
Download these files into the matching paths in your project, or use Create to assemble a kit. Include each dependency once. Do not also load app.css.
<link rel="stylesheet" href="/library/assets/base.css">
<link rel="stylesheet" href="/library/assets/field.css">
<link rel="stylesheet" href="/library/assets/datepicker.css">
<script defer src="/library/assets/datepicker.js"></script>18,657 bytes CSS including base · 30,276 bytes runtime JavaScript
Usage
Start with a real date field
Use a visible label and input type="date". Clicking the field or calendar button opens the picker; Tab focus keeps direct keyboard entry available. The small calendar button is enabled by datepicker.js; native entry still works without it.
Make choosing easy
Click the month or year separately to open a selection grid. Selecting a month or year returns directly to the calendar so you can choose a day. Arrows page through years in month view and groups of 12 years in year view. Muted dates belong to neighboring months and can also be selected. The calendar opens beside its field on desktop and as a compact modal on mobile. Arrows move by day or week; Home/End move to week edges. Page Up/Down changes month; hold Shift to change year. Enter selects. Escape or clicking outside closes without changing the value.
Choose a date range
Wrap two date pickers in data-date-range and mark their inputs data-range-start and data-range-end. Use unique labels, IDs and names. JavaScript combines the fields into one visible range control and one shared calendar. The two native fields remain the submitted values and no-JavaScript fallback. The first selection starts a draft; the second commits both dates together. Escape or outside dismissal discards an unfinished draft. Same-day ranges are allowed. Typed reversed ranges receive native validation and an optional [data-range-error] live message; localize it with data-range-message. Clearing a date removes its ordering constraint. Native min/max/step stay intact. Without JavaScript, both fields still work; validate ordering on the server.
Explain the limits
Set min, max, and step only when needed, and describe the allowed dates before entry. Mark required fields visibly and connect errors with aria-describedby.
Add time when needed
Pair the calendar with a labeled input type="time", or use it alone with base and field styles. For a styled popup, wrap it in .datepicker[data-timepicker] with a hidden labeled button and include the Date picker styles and script. Use data-hour-format="12" for AM/PM or omit it for 24 hours. Valid changes apply immediately; Escape and outside clicks close the picker. Invalid edits do not replace the last valid time. AM/PM and chevrons are disabled when their next change violates min/max/step; invalid typed entries show an error. Native entry works without JavaScript. Use step="60" for minutes or step="1" for seconds, with native min, max, and required constraints. The enhanced text field follows the picker’s 12/24-hour format; submitted values use HH:mm or HH:mm:ss. Explain the scheduling time zone and resolve daylight-saving ambiguity in application code; a local date and time are not a UTC timestamp.
Keep dates as dates
Read and submit YYYY-MM-DD values. A birthday or due date is not a timestamp; converting it through a time zone can shift the day.
Localize the whole experience
Set lang and dir, translate the calendar action labels, and use data-week-start="1" for Monday. The calendar uses Gregorian dates.
Know what is included
This picker selects one date. Time-zone conversion, natural-language parsing, saving, and server validation belong to the application. Check assistive technology and mobile browsers for your audience.
Building with AI? The AI Manifest has these notes and the full contract. See the AI Guide.