Calendar
The Calendar component provides a flexible UI element for displaying a date picker. It’s a styled wrapper around react-day-picker, so it supports single-date, multi-date, and range selection along with bounds and disabled days.
Variations
Single
Pick one date with mode="single".
Multiple
Collect several individual dates with mode="multiple".
Bounded range
Clamp the selectable window with fromDate / toDate; days outside it are disabled.
Installation
import { useState } from 'react';import { Calendar } from '@harnessio/ui/components';
const CalendarExample = () => { const [selectedDate, setSelectedDate] = useState<Date | undefined>(new Date());
return ( <Calendar mode="range" selected={selectedDate} onSelect={setSelectedDate} showOutsideDays fromDate={new Date().setDate(new Date().getDate() - 10)} toDate={new Date().setDate(new Date().getDate() + 10)} weekStartsOn={1} /> );};
export default CalendarExample;Anatomy
Calendar is a single component — there are no sub-parts to compose. Configure it entirely through props:
<Calendar mode="single" // 'single' | 'multiple' | 'range' selected={selected} onSelect={setSelected} showOutsideDays // include muted adjacent-month days weekStartsOn={1} // 0 (Sun) – 6 (Sat) fromDate={min} // clamp the selectable window toDate={max}/>The rendered calendar has three regions:
- Caption & navigation — a centered month/year label with previous/next arrow buttons.
- Weekday header — a row of weekday abbreviations;
weekStartsOnsets which day is the first column. - Day grid — the selectable days.
modedecides whether one day, several separate days, or a contiguous range can be picked, andshowOutsideDaystoggles the muted days that spill in from the adjacent months.
Bounds and exclusions are also props: fromDate/toDate clamp the range of selectable days, and disabled greys out specific dates. Because Calendar is a thin wrapper over react-day-picker’s DayPicker, any DayPicker prop (e.g. month, onMonthChange, numberOfMonths, locale) passes straight through.
Best practices
Do
- Match
modeto the task:singlefor one date,multiplefor a set of discrete dates,rangefor a start/end span. - Constrain the selectable window with
fromDate/toDate(ordisabled) whenever some dates aren’t valid, so people can’t pick an unusable date. - Set
weekStartsOnto match the user’s locale conventions rather than leaving it to chance. - Pair the calendar with a text input or a clear label so the current selection is always visible, especially for ranges.
Don’t
- Don’t use a full calendar for coarse choices like a month or a year — a simpler select is faster.
- Don’t rely on the calendar alone to explain an invalid range; surface the reason a date is disabled nearby.
- Don’t override the calendar’s
classNames/componentswholesale just for a small tweak — you’ll lose the design-system styling and built-in affordances.
Content
- Label the field with the kind of date it collects (“Start date”, “Due date”), not just “Date”.
- When a range is required, make the start/end expectation explicit in the surrounding copy.
- If dates are disabled, say why close to the calendar (“Bookings open 10 days out”) rather than leaving people to discover the limit by clicking.
Accessibility
Calendar is built on react-day-picker, which ships grid semantics and keyboard support out of the box.
Keyboard
- Arrow keys move focus between days; Home/End jump to the start/end of a week and PageUp/PageDown change months.
- The focused day is the single tab stop within the grid; Enter/Space selects it.
- The previous/next month buttons are in the tab order and activate with Enter/Space.
Labeling
- The days render as a
role="grid"table, and each day is a button whose accessible name is its full date; selected days exposearia-selected. - The navigation arrows are icon-only but keep
react-day-picker’s built-in labels (“Go to previous/next month”) — the wrapper only swaps the arrow glyph, not the label.
Focus & states
- Days and the nav buttons reuse the standard button styles, so they show the normal keyboard focus ring.
- Disabled and out-of-range days are dimmed and skipped by keyboard navigation.
Known limitations
- Selection is conveyed largely by color. Selected days, the range start/end, and the range middle are distinguished mainly by background and text color, with no non-color cue at the range boundaries. Assistive tech still gets
aria-selected, but low-vision sighted users may find a long range hard to read. - “Today” is bold only. The current day is styled with bold weight and nothing else, so it can be easy to miss visually against the other days.
- Overrides pass straight through to
react-day-picker.classNamesandcomponentsare merged into the underlyingDayPicker, so replacingcomponents.IconLeft/IconRightor coreclassNamescan drop the design-system styling and the built-in nav labels. Override sparingly.
Properties
Calendar accepts every react-day-picker DayPicker prop; the most commonly used ones are listed below.
Prop | Required | Default | Type |
|---|---|---|---|
| mode | false | 'single' | 'single' | 'multiple' | 'range' |
| selected | false | Date | Date[] | { from: Date; to: Date } | |
| onSelect | false | (date: Date | Date[] | { from: Date; to: Date }) => void | |
| showOutsideDays | false | true | boolean |
| className | false | string | |
| classNames | false | ClassNames | |
| components | false | CustomComponents | |
| disabled | false | Date | Date[] | { from: Date; to: Date } | |
| fromDate | false | Date | |
| toDate | false | Date | |
| locale | false | Locale | |
| weekStartsOn | false | 0 | 1 | 2 | 3 | 4 | 5 | 6 |