Skip to content

DatePicker

Terminal window
$ npx shadcn@latest add https://lacodda.github.io/dowel/r/date-picker.json
See it liveEmpty, chosen, bounded, and inside a Field.→

The trigger is a button, not a typable field. A date input has to answer “what does 03/04/26 mean” in a locale it cannot be sure of, and it answers wrong for half the world. A button showing the date spelled out has no such question. Where typing genuinely matters — a birth date forty years back — a calendar is the wrong control anyway.

<DatePicker
value={releasedOn} // '2026-09-02'
onValueChange={setReleasedOn}
placeholder="Pick a date"
previousMonthLabel="Previous month"
nextMonthLabel="Next month"
/>

What is shown is Intl’s own long form — “2 September 2026” here, “September 2, 2026” in the United States. The stored value never changes.

It closes when a day is chosen. Choosing is the whole errand; waiting for a second dismissing click is one click too many.

An optional date can be taken back. Give clearLabel and, while a day is chosen, the popup offers it under the month in your words; onValueChange is then told undefined. In the popup rather than as a cross on the field: the trigger is a button and cannot hold another, and a cross laid over it is a second, smaller target against the first. A required field gives no words and cannot be emptied - and the type agrees: only a picker given clearLabel takes a handler that has to deal with no date.

<DatePicker value={due} onValueChange={setDue} clearLabel={t('clear')} ... />

name puts the value where a form can find it. A button is not a field, so without it a form submits the screen and loses the date — the component writes a hidden input instead.

<DatePicker name="released_on" ... /> // submits 2026-09-02

Inside a Field the label names the trigger. The id the label points at and the two aria- references go on the button, and the button is named by the label and then the date - “Release, 2 September 2026” - rather than by the date alone. A press on the label opens the month.

<Field label="Release" help="The day it goes out.">
<DatePicker value={releasedOn} onValueChange={setReleasedOn} ... />
</Field>

The value, the arithmetic and the keyboard are the Calendar’s; this is the field around it.

Props

Read from the types in ui/date-picker.tsx, the file a product copies - so the description of each prop is also what an editor shows over it there.

PropTypeDefault
clearLabelstringThe words of the button that takes the date back: "Clear". Leave it out and a chosen date stays chosen - the shape of a required field.
onValueChange(value: string | undefined) => void | (value: string) => voidTold the chosen day, or undefined when it is taken back.
valuestringThe chosen day, or undefined for none.
minstringThe earliest day that can be chosen, inclusive.
maxstringThe latest day that can be chosen, inclusive.
placeholderrequiredstringWhat the trigger says when nothing is chosen. The product's word, since a default here would be English inside a primitive.
previousMonthLabelrequiredstringNames the two month-paging buttons inside the calendar.
nextMonthLabelrequiredstringNames the next-month paging button inside the calendar.
localestringHow the date is written and which day starts the week. The application's language unless stated - see useLocale.
disabledbooleanfalseStops the trigger opening the calendar.
namestringPuts the value in a form: a hidden input of this name carries the date, because the trigger is a button and a form would otherwise lose it.
idstringPut on the trigger, so a Field label can point at it.
aria-labelstringThe accessible name of the field, in place of a visible label.
aria-labelledbystringPoints at the element that names the field; a Field label hands this over. The date shown on the trigger is added to the name.
aria-describedbystringPoints at the hint or error text, put on the trigger.
aria-invalidtrue | false | booleanMarks the trigger as holding an invalid value.
classNamestring

Accessibility

The examples on the stand, through axe 4.14.0 in a browser, in both themes, against WCAG 2.2 A and AA and axe's best practices: 15 rules applied and passed, and none failed. The accessibility report has every item.

History

Each release that changed ui/date-picker.tsx - the file a product copies - newest first.

  1. v0.41.0
    • docs read every props table from the component's types ee3b159
  2. v0.40.0
    • refactor say state on the element, and measure the palette's anchor apart 8d9b4e1
    • fix put the calendar's cursor on the focus, and open a picker on the day fe23f69
  3. v0.38.0breaking
    • feat take a chosen date back 13d7dd1
  4. v0.37.0
    • fix name the trigger by its label and its date 96662d8
  5. v0.31.0breaking
    • feat dates and numbers in the application's language 9be5f95
  6. v0.28.0breaking
    • feat density as a property of a region 849d783
  7. v0.18.1
    • feat dates, on Intl rather than on a date library 5ec8403