Skip to content
Tier

Date picker

Pro

A button that opens a calendar in a popover and shows the chosen day. Nothing is chosen until the person picks; the button then reads the exact date in the locale ("8 Nov 2026"). Shortcuts like "Tomorrow" are allowed, but each prints the exact date beside its words and the button only ever shows the date, never the phrase. Escape closes the popover and focus returns to the button.

Markdown
Version 5.2.0· other versions

This page is for 5.2.0, the current release. An earlier release’s page is the Markdown that release published, so the docs match the version you have installed (candor-lock.json records it).

Not in the docs of 1.3.0, 1.4.0, 1.5.0, 1.5.1, 1.6.0, 1.7.0, 1.8.0, 1.8.1, 1.9.0, 1.9.1, 2.0.0, 2.1.0 and 2.2.0: the page came later, or had another name then.

Docs pages weren’t kept for 1.0.0, 1.0.1, 1.1.0, 1.1.1, 1.2.0 and 1.2.1: they are kept from 1.3.0 on, and before that only llms.txt was published.

Preview

Loading the preview

Install

With the Candor CLI

First time? Get started sets up the registry and theme. Or with shadcn directly: npx shadcn@latest add @candor/date-picker

Brings in: button, calendar, locale, locked, popover, tokens, utils · npm: lucide-react@^1.67.0

Usage

TSX · The example above
"use client"

import * as React from "react"
import { DatePicker } from "@/components/candor/ui/date-picker"

// "Tomorrow" is a phrase; the picker prints the exact date beside it, and the button only ever shows the date.
const today = new Date(2026, 10, 8)
const at = (days: number) => new Date(2026, 10, 8 + days)

export default function Example() {
  const [due, setDue] = React.useState<Date | undefined>()
  return (
    <div className="flex flex-col items-start gap-2">
      <label htmlFor="due" className="text-sm font-medium">
        Due date
      </label>
      <DatePicker
        id="due"
        value={due ?? null}
        onValueChange={setDue}
        today={today}
        defaultMonth={today}
        clearable
        presets={[
          { label: "Tomorrow", date: at(1) },
          { label: "In a week", date: at(7) },
          { label: "In a month", date: new Date(2026, 11, 8) },
        ]}
      />
    </div>
  )
}

<DatePicker>

PropTypeDefaultDescription
valueDate | null | undefined—The chosen day, when you control it. `null` is nothing chosen.
defaultValueDate | undefined—The day chosen at first, when you don't control it. Left out, nothing is chosen.
onValueChange((date: Date | undefined) => void) | undefined—Called with the day a person picks, or `undefined` when they clear it.
presetsDatePreset[] | undefined—Shortcuts shown beside the calendar, each with its exact date.
unavailable((date: Date) => string | null | undefined | false) | undefined—Returns why a day can't be picked, or nothing when it can; passed to the calendar.
clearableboolean | undefinedfalseShows a "Clear date" button once a day is chosen.
lockedstring | null | undefined—Why the picker can't be used right now. The button stays focusable and says why.
placeholderstring | undefined—Text on the button while nothing is chosen. Defaults to "Pick a date".
defaultMonthDate | undefined—The month the calendar opens on when nothing is chosen. Defaults to today's.
todayDate | undefined—The day to outline as today in the calendar.
idstring | undefined——
classNamestring | undefined—Classes, merged with Candor's.
"aria-label"string | undefined—The button's accessible name when it needs one beyond its text (the field's label).

Strings

The fixed words, in English by default. Change any of them under datePicker in <LocaleProvider strings={{ … }}>; the table is exported as datePickerStrings.

KeyEnglish
placeholderPick a date
presetsShortcuts
clearClear date

Motion

MomentFamilyWhat it does
tinttintA shortcut's background changes when the pointer is over it, and a ring fades in when it takes keyboard focus.

Set with --cd-motion-date-picker-<moment>-* in your brand file; the families are in the design reference.

Types

DatePreset
A shortcut such as "Tomorrow" or "In 7 days". The exact date is always printed beside the words.
{ /** The relative phrase: "Tomorrow", "Next Monday". */ label: string; /** The day it means, worked out by the app. Shown beside the label so nobody has to guess what "next week" is. */ date: Date; }