XDSCalendar@xds/core · Calendar
Usage
Calendar lets the user pick a date or date range from a month grid. Use it in booking flows, scheduling UIs, date filters, or anywhere the user needs to see surrounding dates for context.Best practices
| Guidance | Practices |
|---|---|
| Do | Set min and max dates to limit selection to a valid window — like only future dates for a booking or the current quarter for a report. |
| Do | Use range mode when the user needs to pick a start and end date, like a trip or a time-off request. |
| Do | Use dateConstraints to disable specific dates like weekends or holidays, and explain why they are unavailable. |
| Do | Show two months side by side when the user frequently selects dates that span a month boundary. |
| Don't | Use a calendar for dates far in the past or future like a birth date — a text input is faster for open-ended entry. |
| Don't | Disable large blocks of dates without context — the user should understand why dates are unavailable. |
Anatomy
| Element | Description | |
|---|---|---|
| Month header | required | The month name and year with navigation arrows to move between months. |
| Day grid | required | A 7-column grid of days with column headers for the day names. |
| Selected day | The currently selected date, highlighted. In range mode, the start and end dates plus the days between them. | |
| Today marker | A subtle indicator on the current date for orientation. |
Import
tsimport {XDSCalendar} from '@xds/core/Calendar'
Props
| Prop | Type | Description |
|---|---|---|
mode | 'single' | 'range' (default: 'single') | Selection mode. |
value | ISODateString | DateRange | Controlled selected value. |
defaultValue | ISODateString | DateRange | Uncontrolled default value. |
onChange | Function | Selection callback. |
numberOfMonths | 1 | 2 (default: 1) | Number of months to display. |
min | ISODateString | Minimum selectable date. |
max | ISODateString | Maximum selectable date. |
dateConstraints | Array<(date: Date) => boolean> | Custom constraint functions. |
focusDate | ISODateString | Controlled visible month. |
onFocusDateChange | (focusDate: ISODateString) => void | Navigation callback. |
hasOutsideDays | boolean (default: true) | Show days from adjacent months. |
hasWeekNumbers | boolean (default: false) | Show ISO week numbers. |
hasVariableRowCount | boolean (default: false) | Variable vs fixed 6-row grid. |
weekStartsOn | 0 | 1 | 2 | 3 | 4 | 5 | 6 (default: 0) | First day of week (0=Sunday). |
Examples
Common configurations, variations, and states.Calendar — ConstraintsLimit which dates can be selected using min/max bounds and custom rules like weekdays only. Use for scheduling UIs where certain dates are unavailable.
tsx'use client';import {useState} from 'react';import {XDSCalendar, type ISODateString} from '@xds/core/Calendar';import {XDSStack} from '@xds/core/Layout';import {XDSText} from '@xds/core/Text';const isWeekday = (date: Date) => {const day = date.getDay();return day !== 0 && day !== 6;};export default function CalendarConstraints() {const [value, setValue] = useState<ISODateString | undefined>(undefined);return (<XDSStack direction="vertical" gap={4} hAlign="center"><XDSText type="supporting" color="secondary">Jan 10 – Mar 20, weekdays only</XDSText><XDSCalendarmode="single"min={'2026-01-10' as ISODateString}max={'2026-03-20' as ISODateString}dateConstraints={[isWeekday]}value={value}onChange={val => setValue(val)}focusDate={'2026-01-01' as ISODateString}/></XDSStack>);}
Calendar — RangePick a start and end date with the range highlighted between them. Use for booking dates, time-off requests, or report filters.
tsx'use client';import {useState} from 'react';import {XDSCalendar, type DateRange} from '@xds/core/Calendar';import {XDSStack} from '@xds/core/Layout';import {XDSText} from '@xds/core/Text';export default function CalendarRangeWithValue() {const [value, setValue] = useState<DateRange>({start: '2026-01-10',end: '2026-01-20',});return (<XDSStack direction="vertical" gap={4} hAlign="center"><XDSText type="supporting" color="secondary">{value.start && value.end? `${value.start} → ${value.end}`: 'Pick a start and end date'}</XDSText><XDSCalendarmode="range"value={value}onChange={range => setValue(range)}focusDate="2026-01-01"/></XDSStack>);}
Calendar — SinglePick one date from a month grid. Use for appointment dates, due dates, or any field that needs a single date.
tsx'use client';import {useState} from 'react';import {XDSCalendar, type ISODateString} from '@xds/core/Calendar';import {XDSStack} from '@xds/core/Layout';import {XDSText} from '@xds/core/Text';export default function CalendarSingle() {const [value, setValue] = useState<ISODateString>('2026-01-15');return (<XDSStack direction="vertical" gap={4} hAlign="center"><XDSText type="supporting" color="secondary">{value ? `Selected: ${value}` : 'Pick a date'}</XDSText><XDSCalendarmode="single"value={value}onChange={val => setValue(val)}focusDate="2026-01-01"/></XDSStack>);}
Calendar — Two MonthsTwo months side by side for selecting ranges that span a month boundary. Use in booking or travel UIs where check-in and check-out often fall in different months.
tsx'use client';import {useState} from 'react';import {XDSCalendar, type DateRange} from '@xds/core/Calendar';import {XDSStack} from '@xds/core/Layout';import {XDSText} from '@xds/core/Text';export default function CalendarTwoMonths() {const [value, setValue] = useState<DateRange>({start: '2026-01-25',end: '2026-02-05',});return (<XDSStack direction="vertical" gap={4} hAlign="center"><XDSText type="supporting" color="secondary">{value.start && value.end? `${value.start} → ${value.end}`: 'Pick a date range'}</XDSText><XDSCalendarmode="range"numberOfMonths={2}value={value}onChange={range => setValue(range)}focusDate="2026-01-01"/></XDSStack>);}
Showcase source
tsx'use client';import {useState} from 'react';import {XDSCalendar} from '@xds/core/Calendar';import type {ISODateString} from '@xds/core/Calendar';export default function CalendarShowcase() {const [value, setValue] = useState<ISODateString | undefined>('2026-04-15');return <XDSCalendar mode="single" value={value} onChange={setValue} />;}