InlineCalendar
A calendar that is always on the page, for one day, several days or a range.
SourcePackage @weft-js/warp
Preview
tsx
import { state } from '@weft-js/core'import { InlineCalendar, Stack, Text } from '@weft-js/warp'import type { IsoDate } from '@weft-js/warp'export function Single() { const day = state<IsoDate | null>('2026-11-12') return ( <Stack gap="related"> <InlineCalendar aria-label="Release day" today={TODAY} value={day} /> <Text subtle role="caption">Release day: {day.value ?? 'not set'}</Text> </Stack> )}const TODAY: IsoDate = '2026-11-02'Installation
npm install @weft-js/warpUsage
tsx
import { InlineCalendar } from '@weft-js/warp'Selection
A range over two months
Press a start, then an end.
tsx
import { state } from '@weft-js/core'import { InlineCalendar, Stack, Text } from '@weft-js/warp'import type { DateRange, IsoDate } from '@weft-js/warp'export function Range() { const away = state<DateRange>({ start: '2026-11-23', end: '2026-12-04' }) return ( <Stack gap="related"> <InlineCalendar aria-label="Time away" selection="range" months={2} today={TODAY} value={away} /> <Text subtle role="caption">Away from {away.value.start ?? '…'} to {away.value.end ?? '…'}</Text> </Stack> )}const TODAY: IsoDate = '2026-11-02'Several days
Each press turns a day on or off.
tsx
import { state } from '@weft-js/core'import { InlineCalendar, Stack, Text } from '@weft-js/warp'import type { IsoDate } from '@weft-js/warp'export function Multiple() { const days = state<IsoDate[]>(['2026-11-03', '2026-11-05', '2026-11-10']) return ( <Stack gap="related"> <InlineCalendar aria-label="Office days" selection="multiple" today={TODAY} value={days} /> <Text subtle role="caption">{days.value.length} office days</Text> </Stack> )}const TODAY: IsoDate = '2026-11-02'Booking around taken days
Use isDateUnavailable to block days that are taken, and min and max to limit the range.
tsx
import { InlineCalendar } from '@weft-js/warp'import type { IsoDate } from '@weft-js/warp'export function Booking() { return ( <InlineCalendar aria-label="Pick a day for the audit" today={TODAY} defaultValue="2026-11-18" min={TODAY} max="2026-12-20" isDateUnavailable={booked} firstDayOfWeek={1} weekNumbers /> )}const min = 60_000const TODAY: IsoDate = '2026-11-02'const isWeekend = (d: IsoDate) => [0, 6].includes(new Date(`${d}T12:00Z`).getUTCDay())const booked = (d: IsoDate) => isWeekend(d) || ['2026-11-11', '2026-11-12', '2026-11-26'].includes(d)When to use
Accessibility
- Arrows
- Move by day or week
- PageUp/PageDown
- Change the month
- Home/End
- Go to the start or end of the week
- EnterorSpace
- Picks the day
- It has no visible label, so
aria-labelis required. - Every day button says the full date and its state.
API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
value | InlineCalendarValue | State<InlineCalendarValue> | — | The current value, when you own the state. |
defaultValue | InlineCalendarValue | — | The starting value, when the component owns the state. |
selection | "single" | "multiple" | "range" | 'single' | single, multiple or range. The value changes shape to match. |
months | 2 | 3 | 1 | 1 | One to three months side by side. |
min | string | — | The lowest allowed value. |
max | string | — | The highest allowed value. |
isDateUnavailable | ((d: `${number}-${number}-${number}`) => boolean) | — | Return true for a day that can't be picked: it shows struck through. |
firstDayOfWeek | number | — | The day each row starts on, 0 for Sunday to 6. The locale's otherwise. |
weekNumbers | boolean | false | Shows the week number at the start of each row. |
locale | string | — | The language and region used to format values. |
today | string | — | Pins today's date, for server rendering and tests. The browser's clock otherwise. |
aria-label | string | — | Names the calendar for screen readers, since it has no visible label. |
| Event | Type | Default | Description |
|---|---|---|---|
onValueChange | ((v: InlineCalendarValue, reason: ChangeReason) => void) | — | Called with each new value, and whether a pointer, a key or code made the change. |