Skip to content
weftGitHub

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/warp

Usage

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

Use it for

  • Booking and availability, where the month is the point

Reach for something else

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-label is required.
  • Every day button says the full date and its state.

API Reference

PropTypeDefaultDescription
valueInlineCalendarValue | State<InlineCalendarValue>—The current value, when you own the state.
defaultValueInlineCalendarValue—The starting value, when the component owns the state.
selection"single" | "multiple" | "range"'single'single, multiple or range. The value changes shape to match.
months2 | 3 | 11One to three months side by side.
minstring—The lowest allowed value.
maxstring—The highest allowed value.
isDateUnavailable((d: `${number}-${number}-${number}`) => boolean)—Return true for a day that can't be picked: it shows struck through.
firstDayOfWeeknumber—The day each row starts on, 0 for Sunday to 6. The locale's otherwise.
weekNumbersbooleanfalseShows the week number at the start of each row.
localestring—The language and region used to format values.
todaystring—Pins today's date, for server rendering and tests. The browser's clock otherwise.
aria-labelstring—Names the calendar for screen readers, since it has no visible label.
EventTypeDefaultDescription
onValueChange((v: InlineCalendarValue, reason: ChangeReason) => void)—Called with each new value, and whether a pointer, a key or code made the change.

RelatedDate fieldDate range fieldCalendar