Starting Point
v0.35.0

Search documentation

Search for a page and jump to it.

Start typing to search...
Go to Page
escClose

Tailwind CSS Date Picker

Use the date picker component to pick a date or a date range from a popup calendar, like a due date, a booking, or a date of birth. For a calendar that stays visible on the page, use the calendar.

<div class="date-picker">
  <input type="date" name="date" />
  <button id="date-picker-demo" class="btn btn-outline w-53 justify-between font-normal">
    <span class="date-picker-value" data-sp-placeholder="Pick a date"></span>
    <svg class="icon-end" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg>
  </button>
</div>

Usage

Add the date-picker class to a wrapper holding a native <input type="date"> and a button. Give the button date-picker-trigger to make it look like a form field, or style it as any button. Put an empty date-picker-value span in the button with the placeholder in data-sp-placeholder. The popover and calendar are built for you, and the input keeps submitting with the form. When the server has a saved value, set it on the input and write the formatted date into the span, so the page paints right before any JavaScript runs.

ClassDescription
date-pickerAdd to the wrapper around the input and the trigger, which carries the data-sp-* options
date-picker-triggerAdd to the button for a field look, like a select, with a chevron and the invalid ring
date-picker-trigger-smAdd to date-picker-trigger for a compact field
date-picker-valueAdd to the span in the trigger that shows the picked date, or its data-sp-placeholder
date-picker-popoverRendered on the popover holding the calendar
<div class="date-picker">
  <input type="date" name="date" />
  <button class="date-picker-trigger">
    <span class="date-picker-value" data-sp-placeholder="Pick a date"></span>
  </button>
</div>

Examples

Basic date picker

Wrap the picker in a field and point the label at the trigger. date-picker-trigger gives the button the same look as an input or select.

<div class="field w-44">
  <label class="label" for="date-picker-basic">Date</label>
  <div class="date-picker">
    <input type="date" name="date" />
    <button id="date-picker-basic" class="date-picker-trigger">
      <span class="date-picker-value" data-sp-placeholder="Pick a date"></span>
    </button>
  </div>
</div>

Date picker sizes

Add date-picker-trigger-sm to match input-sm and select-sm.

<div class="field w-44">
  <label class="label" for="date-picker-small">Date</label>
  <div class="date-picker">
    <input type="date" name="date" />
    <button id="date-picker-small" class="date-picker-trigger date-picker-trigger-sm">
      <span class="date-picker-value" data-sp-placeholder="Pick a date"></span>
    </button>
  </div>
</div>

Date range picker

Two date inputs make a range picker, shown here with data-sp-months="2".

<div class="field w-60">
  <label class="label" for="date-picker-range">Date Picker Range</label>
  <div class="date-picker" data-sp-months="2">
    <input type="date" name="from" value="2026-01-20" />
    <input type="date" name="to" value="2026-02-09" />
    <button id="date-picker-range" class="date-picker-trigger">
      <svg class="icon-start" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 2v4"/><path d="M16 2v4"/><rect width="18" height="18" x="3" y="4" rx="2"/><path d="M3 10h18"/></svg>
      <span class="date-picker-value" data-sp-placeholder="Pick a date"></span>
    </button>
  </div>
</div>

Multiple date picker

Add multiple to the input to pick several dates, and the trigger counts them.

<div class="field w-44">
  <label class="label" for="date-picker-multiple">Dates</label>
  <div class="date-picker">
    <input type="date" name="dates" multiple />
    <button id="date-picker-multiple" class="date-picker-trigger">
      <span class="date-picker-value" data-sp-placeholder="Pick dates"></span>
    </button>
  </div>
</div>

Date of birth picker

Add data-sp-caption="dropdown" to jump between years, and cap the range with data-sp-max="today".

<div class="field w-44">
  <label class="label" for="date-picker-dob">Date of birth</label>
  <div class="date-picker" data-sp-caption="dropdown" data-sp-max="today">
    <input type="date" name="dob" />
    <button id="date-picker-dob" class="date-picker-trigger">
      <span class="date-picker-value" data-sp-placeholder="Select date"></span>
    </button>
  </div>
</div>

Date and time picker

Put a native time input next to the picker, and the two submit as separate fields.

<div class="field-group max-w-xs flex-row">
  <div class="field">
    <label class="label" for="date-picker-time">Date</label>
    <div class="date-picker" data-sp-caption="dropdown">
      <input type="date" name="date" />
      <button id="date-picker-time" class="date-picker-trigger w-32">
        <span class="date-picker-value" data-sp-placeholder="Select date"></span>
      </button>
    </div>
  </div>
  <div class="field w-32">
    <label class="label" for="time-picker-time">Time</label>
    <input
      class="input appearance-none bg-background [&::-webkit-calendar-picker-indicator]:hidden [&::-webkit-calendar-picker-indicator]:appearance-none"
      id="time-picker-time"
      type="time"
      name="time"
      step="1"
      value="10:30:00"
    />
  </div>
</div>

Date picker with disabled dates

Every calendar option works on the wrapper, like data-sp-disabled for weekends and booked days.

<div class="field w-44">
  <label class="label" for="date-picker-disabled">Appointment</label>
  <div
    class="date-picker"
    data-sp-month="2026-03"
    data-sp-min="2026-03-02"
    data-sp-disabled="sat,sun,2026-03-16..2026-03-20"
  >
    <input type="date" name="appointment" />
    <button id="date-picker-disabled" class="date-picker-trigger">
      <span class="date-picker-value" data-sp-placeholder="Pick a weekday"></span>
    </button>
  </div>
</div>

RTL

Add dir="rtl" to any parent element, typically <html>, to render right-to-left. Pair it with a matching data-sp-locale. See the RTL guide for details.

<div id="date-picker-rtl-demo" dir="rtl">
  <div class="date-picker" data-sp-locale="ar-EG">
    <input type="date" name="date" />
    <button id="date-picker-rtl" class="btn btn-outline w-53 justify-between font-normal">
      <span class="date-picker-value" data-sp-placeholder="اختر تاريخًا"></span>
      <svg class="icon-end" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg>
    </button>
  </div>
</div>
 
<script>
  const demo = document.getElementById("date-picker-rtl-demo");
  const template = demo.innerHTML;
  const translations = {
    ar: { dir: "rtl", locale: "ar-EG", placeholder: "اختر تاريخًا" },
    he: { dir: "rtl", locale: "he-IL", placeholder: "בחר תאריך" },
    en: { dir: "ltr", locale: "en-US", placeholder: "Pick a date" },
  };
  window.addEventListener("message", (e) => {
    const t = translations[e.data?.lang];
    if (e.data?.type !== "sp-language" || !t) return;
    demo.dir = t.dir;
    demo.innerHTML = template;
    const picker = demo.querySelector(".date-picker");
    picker.setAttribute("data-sp-locale", t.locale);
    picker.querySelector(".date-picker-value").setAttribute("data-sp-placeholder", t.placeholder);
    sp.datePicker(picker).show();
  });
</script>

Options

Set each option with its own data-sp-* attribute on the date-picker element. The calendar options are passed through to the calendar inside, see the calendar page for their details.

AttributeValuesDefault
data-sp-placementFloating UI placementbottom-start
data-sp-offsetNumber6
data-sp-align-offsetNumber0
data-sp-localeBCP 47 language tagThe page lang
data-sp-monthYYYY-MMThe selected or current month
data-sp-monthsNumber1
data-sp-captionlabel | dropdownlabel
data-sp-week-numbersBooleanfalse
data-sp-week-start0 (Sunday) to 6 (Saturday)0
data-sp-minYYYY-MM-DD | todayNone
data-sp-maxYYYY-MM-DD | todayNone
data-sp-disabledComma-separated dates, from..to ranges, weekday namesNone

The placeholder is the one option that lives on the date-picker-value span instead.

AttributeValuesDefault
data-sp-placeholderTextNone
<div
  class="date-picker"
  data-sp-placement="bottom-end"
  data-sp-caption="dropdown"
  data-sp-max="today"
>
  <input type="date" name="date" />
  <button class="date-picker-trigger">
    <span class="date-picker-value" data-sp-placeholder="Pick a date"></span>
  </button>
</div>

JavaScript

Events

sp-change bubbles up from the calendar, so listen for it on the date-picker element. Its detail is { value } for a single date, { from, to } for a range, and { values } for multiple dates. The popover lifecycle events fire on the rendered popover.

EventWhen
sp-changeThe selection changed
el.addEventListener("sp-change", (e) => {
  console.log(e.detail.value);
});

Methods

Get the instance with sp.datePicker(el), then call its methods:

MethodDescription
value()The ISO value, { from, to } for a range, array for multiple
select(value)Select an ISO date, { from, to }, or an array of dates
clear()Clear the selection
show()Open the calendar
hide()Close the calendar
toggle()Open if closed, else close
const picker = sp.datePicker(document.querySelector("#my-picker"));
 
picker.select("2026-12-24");