Date picker
A calendar panel for picking one date or a date range, with month and year menus.
import { DatePicker } from "@/ui";DatePicker matches the Figma Date Picker component, including its day, month and year cells. It is the panel only. Put it in a popover under the field or button that opens it.
The examples on this page fix today at Dec 11, 2024, to match Figma. In the app, leave today out and it uses the real date.
Single date
Click a day to pick it. Today has a blue outline, and the picked day is filled blue. The arrows change the month.
const [date, setDate] = useState(null);
<DatePicker value={date} onChange={setDate} />With Cancel and Apply
With footer, picks are a draft until the person clicks Apply. Use it when a change reloads data, such as a dashboard's date filter.
<DatePicker value={applied} footer onApply={setApplied} onCancel={close} />Range
mode="range" shows two months side by side. The first click sets the start, the second sets the end, and the days between turn light blue. A click before the start swaps them. While you choose the end, the range follows the pointer.
const [range, setRange] = useState({ from: null, to: null });
<DatePicker mode="range" value={range} onChange={setRange} />Use months={1} when the range fits in one month or space is tight.
In a popover
Open the picker under a trigger that shows the current value. With a footer, Apply closes it.
<Button variant="secondaryGhost" label="Nov 1, 2024 โ Nov 30, 2024" onClick={toggle} />
{open && (
<DatePicker mode="range" value={range} footer onApply={(r) => { setRange(r); close(); }} onCancel={close} />
)}Month and year menus
Click the month or the year in the header to jump. The current month and year are blue, and the one on screen is filled. The year list scrolls to the selected year.
Cells
| Cell | Rest | Hover | Selected |
|---|---|---|---|
| Day | #757A97 text | Primary 50 fill, Primary 500 text | Primary 500 fill, white text |
| Today | Adds a 1px Primary 500 border | ||
| Day in a range | Primary 50 fill, square corners | ||
| Month or year | #757A97 text (Primary 500 when current) | Primary 50 fill, Primary 500 text | Primary 500 fill, white text |
Anatomy
| Part | Spec |
|---|---|
| Panel | 264px wide (512px for two months), 12px padding, 8px radius, white, shadow 0 8px 12px at 10% |
| Header | 20px blue arrows. Month and year in 14px medium, each with a 12px caret |
| Weekdays | 12px primary text, Sunday first |
| Days | 32px tall, 8px radius, 12px text, 4px between weeks |
| Month and year menus | 80px wide, 8px padding, 4px gaps, items 2px 20px with a 4px radius |
| Footer | ghost Cancel and secondary Apply, both sm |
Figma's footer buttons use 10px text. Code uses sm Buttons, which are 12px, because 12px is the smallest text in the product.
Props
| Prop | Type | Default | Notes |
|---|---|---|---|
mode | "single" | "range" | "single" | |
value | Date | null or { from, to } | Controlled value. | |
defaultValue | same as value | Uncontrolled start value. | |
onChange | function | Every pick without a footer; on Apply with one. | |
months | 1 | 2 | 1, or 2 for a range | |
footer | boolean | false | Cancel and Apply. Apply stays disabled until the pick is complete. |
onApply | function | Gets the draft. | |
onCancel | function | The draft resets to value. | |
today | Date | now | |
yearRange | [number, number] | 10 years back to 5 ahead | Years in the year menu. |
className | string | "" | For layout only. |
Accessibility
- Every day is a button labelled with the full date, such as "Wednesday, December 11, 2024". Picked days have
aria-pressed, and today hasaria-current="date". - Only one day is in the tab order. Arrow keys move by a day or a week, Home and End go to the start or end of the week, and Page Up and Page Down change the month. The view follows the focus.
- The month and year menus are listboxes. Escape or a click outside closes them.
Do and don't
- Do show the chosen date or range on the trigger, so people can see it without opening the picker.
- Do use the footer when picking reloads data.
- Don't use a date picker for a fixed set of periods like "Last 7 days". Use a Dropdown.