Calendar
NewA month of days to pick from, inline on the page: one day, or a first and a last. It is the calendar inside DatePicker and DateRangePicker, for when the date is the main thing on screen rather than one field in a form.
Picking a day
Each day is a pill that tints on hover. Today carries a teal satellite under its numeral, and the chosen day fills with Orbit teal, the disc settling into place. Days that cannot be picked fade to mist. Weeks start on Monday, and month and day names come from Intl in British English.
Here a customer picks a collection day: from tomorrow, never on a Sunday. required keeps the chosen day when it is pressed again, rather than clearing it.
Days and their states
Every state a day can be in, light and dark side by side. Hover and focus are live: point at a day, or Tab into the grid and use the arrows.
| State | Looks like |
|---|---|
| Today | A teal satellite under the numeral, which turns semibold. |
| Chosen | A teal disc (mint in dark) with the numeral in white, settling in on the spring. |
| Hover and press | The quiet hover tint, then a deeper tint as the pill dips under the finger. |
| Focus | A 2px teal ring, 2px off the pill, for keyboard focus only. |
| Range | A teal wash between the two filled ends, rounded off at the edges of each week. The numerals stay ink. |
| Picking a range | While the second end is picked, a fainter wash follows the pointer (or focus) to a teal ring. |
| Unavailable | Numerals in mist, no hover, and the arrow keys pass over them. |
| Other months | With one month showing, the days of the months either side fill its first and last weeks, a step quieter, and can still be picked. |
Ranges
mode="range" picks a first and a last day. The first click starts the range and onChange gets { from }; the second completes it as { from, to }, swapping the ends if the second day is earlier; the next click starts again. Both ends are local midnight, and both are included.
numberOfMonths sets months side by side. With more than one, the days of other months are left out, so no day appears twice. Here, the shop's Christmas closure.
Language and the start of the week
locale takes a BCP 47 tag. Month and weekday names come from Intl, and so does the first day of the week: Monday in British English, Sunday in American English. weekStartsOn overrides it, 0 being Sunday.
What the calendar reads out (Previous month, Next month, Today, selected) is English by default: pass translations through labels.
Keyboard
The grid is one Tab stop: focus lands on the chosen day, or today, or the first day that can be picked.
| Key | What it does |
|---|---|
| Left and right arrows | Move a day, into the next or previous month at the edges. They swap in right-to-left layouts. |
| Up and down arrows | Move a week. |
| Page Up, Page Down | Move a month. With Shift, a year. |
| Home, End | Move to the start or the end of the week. |
| Enter, Space | Pick the focused day. |
| Tab | Moves between the previous and next buttons and the grid. |
Guidelines
- Use the calendar inline when picking the date is the task on the screen: a collection day, a closure, days to block out. In a form, where the date is one answer among several, use DatePicker.
- Name it: an
aria-label, oraria-labelledbypointing at a visible heading. - Say what the choice means beside it, in words: "Ready to collect on Thu, 8 Oct 2026". A filled disc alone is easy to miss.
- Rule out what cannot be picked rather than rejecting it afterwards, and say why nearby ("Weekdays only").
- Keep weeks starting on Monday for UK merchants; only change the locale for people who read another one.
Accessibility
- Each month is a
gridnamed by its month and year, with a column header for each weekday. Every day is a button read in full: "Today, Friday, 2 October 2026", with ", selected" when chosen. - The month caption is a polite live region, so moving to another month is announced.
- Previous and next are icon buttons named "Previous month" and "Next month". At the first or last month that can be reached they stay focusable but inert (
aria-disabled), so focus is never dropped. - Unavailable days are disabled buttons, skipped by the arrow keys.
- Colour is never the only signal: today also turns semibold, a chosen day is announced as selected, and a range also reads in the status line beside it.
- Under reduced motion the chosen-day disc appears without settling, a pressed day does not dip, and a new month swaps in without sliding.
Props
Built on react-day-picker 9, styled entirely by the kit (react-day-picker's own stylesheet is not used). Pass className, style, id and dir for the root, and the ref reaches it too.
Calendar
| Prop | Type | Default | Description |
|---|---|---|---|
mode | 'single' | 'range' | 'single' | One day, or a first and a last. |
value | Date | null, or Partial<DateRange> | null | None | Controlled day, or range (to is missing while the second day is picked). |
defaultValue | Date | null, or Partial<DateRange> | null | None | Starting value when uncontrolled. |
onChange | (value) => void | None | Every pick. In a range, { from } first, then { from, to }. |
required | boolean | false | Pressing the chosen day keeps it rather than clearing it. |
minValue | Date | null | None | The earliest day that can be picked; months before it cannot be reached. |
maxValue | Date | null | None | The latest day that can be picked; months after it cannot be reached. |
disabled | CalendarMatcher | CalendarMatcher[] | None | Other days that cannot be picked. See Unavailable days. |
excludeDisabled | boolean | false | Range only: start again rather than let a range run across an unavailable day. |
numberOfMonths | number | 1 | Months side by side. |
month, defaultMonth, onMonthChange | Date, Date, (month) => void | None | The month on show. Defaults to the chosen day, or today. |
showOutsideDays | boolean | true with one month | The neighbouring months' days in the first and last weeks. |
fixedWeeks | boolean | true | Always six weeks, so the calendar keeps its height from month to month. |
locale | string | 'en-GB' | BCP 47 tag for month and weekday names and the first day of the week. |
weekStartsOn | 0 to 6 | None | First column of the week, 0 for Sunday. Defaults to the locale's. |
today | Date | None | The day treated as today. Defaults to now. |
autoFocus | boolean | false | Focus the chosen day (or today) on mount. |
labels | Partial<CalendarLabels> | None | previousMonth, nextMonth, today and selected, for translation. |
aria-label, aria-labelledby | string | None | A name for the calendar. |