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
HTML
<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.

Date range

Choose a start date in any month or year.

Choose an end date on or after the start date.

View Code
HTML
<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
HTML
<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
HTML
<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
HTML
<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
HTML
<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
HTML
<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
HTML
<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
HTML
<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
HTML
<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.

Add to your page
<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.