Vize

Range Calendar

Accessible, unstyled two-click date range calendar that reuses the Calendar grid parts.

Package @vizejs/ui/range-calendar
Maturity stable
Own the source vize lib pull range-calendar
Requires calendar, context, controllable-state, id, locale
Aliases date range calendar, booking calendar, two-click range
Covers React Aria RangeCalendar, Reka UI RangeCalendar, WAI-ARIA APG grid

Usage

import { RangeCalendar, RangeCalendarRoot, RangeCalendarGrid, RangeCalendarHeading, RangeCalendarMonthSelect, RangeCalendarNext, RangeCalendarPrev, RangeCalendarYearSelect } from "@vizejs/ui/range-calendar";

Or copy the source into your project with vize lib pull range-calendar (see Source Distribution).

API

RangeCalendar

Source: src/families/date-time/range-calendar/range-calendar-root.vue

Props

Prop Type Default Description
id string | null | undefined undefined Consumer-owned base id; nullish values use a deterministic fallback.
modelValue DateRange | null | undefined undefined Controlled range; undefined selects uncontrolled mode and null clears.
defaultValue DateRange | null | undefined null Initial uncontrolled range.
allowNonContiguousRanges boolean | undefined false Allow committed ranges to span unavailable dates.
focusedDate PlainDate | null | undefined undefined Controlled keyboard focus date; also decides which months are visible.
min PlainDate | null | undefined undefined Earliest selectable date, inclusive.
max PlainDate | null | undefined undefined Latest selectable date, inclusive.
isDateUnavailable DateMatcher | undefined undefined Predicate for dates that stay focusable but cannot be selected.
locale string | undefined undefined BCP 47 locale; defaults to the nearest LocaleProvider.
calendar string | undefined undefined Intl calendar used for display labels only, for example japanese.
numberingSystem string | undefined undefined Intl numbering system for labels.
dir CalendarDirection | undefined undefined Text direction; defaults to the nearest LocaleProvider.
weekStartsOn Weekday | undefined undefined First day of week (0 = Sunday); defaults to the locale preference.
weekdayFormat CalendarWeekdayFormat | undefined "short" Weekday column label width.
numberOfMonths number | undefined 1 Number of consecutive months rendered.
pagedNavigation boolean | undefined false Move month controls by numberOfMonths instead of one month.
fixedWeeks boolean | undefined false Always render six week rows per month.
today PlainDate | null | undefined undefined Explicit current date; the SSR-safe way to mark today.
now DateTimeNow | undefined undefined Injectable clock evaluated during setup on server and client.
timeZone string | undefined undefined IANA time zone used with now and the post-mount host clock.
disabled boolean | undefined false Disable navigation, focus, and selection.
readOnly boolean | undefined false Allow navigation while blocking selection.
startName string | undefined undefined Hidden input name that submits the ISO start date with forms.
endName string | undefined undefined Hidden input name that submits the ISO end date with forms.
ariaLabel string | undefined undefined Accessible name for the calendar group.
ariaLabelledby string | undefined undefined Ids that label the calendar group; defaults to the heading.
ariaDescribedby string | undefined undefined Ids that describe the calendar group.

Events

Event Payload Description
update:modelValue [value: DateRange | null] Fired when the calendar requests a new controlled range.
change [value: DateRange | null, previous: DateRange | null, nativeEvent: Event | null] Fired after a distinct committed range with the previous range and triggering event.
select [value: DateRange, nativeEvent: Event] Fired for every completed range selection, even when the range is unchanged.
anchor-change [anchor: PlainDate | null] Fired when the first endpoint of a new range is picked, or null when cancelled or completed.
update:focusedDate [date: PlainDate] Fired when keyboard or navigation moves the focus date.

Slots

Slot Slot props Description
default CalendarSlotState Range calendar composition. Receives months, weekdays, heading, and state; defaults to a header plus one grid per month.

Exposed

Member Type Description
value —
anchor —
setValue —
cancel —

RangeCalendarRoot

Source: src/families/date-time/range-calendar/range-calendar-root.vue

Props

Prop Type Default Description
id string | null | undefined undefined Consumer-owned base id; nullish values use a deterministic fallback.
modelValue DateRange | null | undefined undefined Controlled range; undefined selects uncontrolled mode and null clears.
defaultValue DateRange | null | undefined null Initial uncontrolled range.
allowNonContiguousRanges boolean | undefined false Allow committed ranges to span unavailable dates.
focusedDate PlainDate | null | undefined undefined Controlled keyboard focus date; also decides which months are visible.
min PlainDate | null | undefined undefined Earliest selectable date, inclusive.
max PlainDate | null | undefined undefined Latest selectable date, inclusive.
isDateUnavailable DateMatcher | undefined undefined Predicate for dates that stay focusable but cannot be selected.
locale string | undefined undefined BCP 47 locale; defaults to the nearest LocaleProvider.
calendar string | undefined undefined Intl calendar used for display labels only, for example japanese.
numberingSystem string | undefined undefined Intl numbering system for labels.
dir CalendarDirection | undefined undefined Text direction; defaults to the nearest LocaleProvider.
weekStartsOn Weekday | undefined undefined First day of week (0 = Sunday); defaults to the locale preference.
weekdayFormat CalendarWeekdayFormat | undefined "short" Weekday column label width.
numberOfMonths number | undefined 1 Number of consecutive months rendered.
pagedNavigation boolean | undefined false Move month controls by numberOfMonths instead of one month.
fixedWeeks boolean | undefined false Always render six week rows per month.
today PlainDate | null | undefined undefined Explicit current date; the SSR-safe way to mark today.
now DateTimeNow | undefined undefined Injectable clock evaluated during setup on server and client.
timeZone string | undefined undefined IANA time zone used with now and the post-mount host clock.
disabled boolean | undefined false Disable navigation, focus, and selection.
readOnly boolean | undefined false Allow navigation while blocking selection.
startName string | undefined undefined Hidden input name that submits the ISO start date with forms.
endName string | undefined undefined Hidden input name that submits the ISO end date with forms.
ariaLabel string | undefined undefined Accessible name for the calendar group.
ariaLabelledby string | undefined undefined Ids that label the calendar group; defaults to the heading.
ariaDescribedby string | undefined undefined Ids that describe the calendar group.

Events

Event Payload Description
update:modelValue [value: DateRange | null] Fired when the calendar requests a new controlled range.
change [value: DateRange | null, previous: DateRange | null, nativeEvent: Event | null] Fired after a distinct committed range with the previous range and triggering event.
select [value: DateRange, nativeEvent: Event] Fired for every completed range selection, even when the range is unchanged.
anchor-change [anchor: PlainDate | null] Fired when the first endpoint of a new range is picked, or null when cancelled or completed.
update:focusedDate [date: PlainDate] Fired when keyboard or navigation moves the focus date.

Slots

Slot Slot props Description
default CalendarSlotState Range calendar composition. Receives months, weekdays, heading, and state; defaults to a header plus one grid per month.

Exposed

Member Type Description
mode CalendarSelectionMode Selection model of the root.
months readonly CalendarMonthState[] Visible month grids; empty while pending.
weekdays readonly CalendarWeekdayLabel[] Localized weekday labels in column order.
heading string Localized heading for the visible months.
focusedDate PlainDate | null Keyboard focus target, or null while pending.
today PlainDate | null Resolved current date, or null before a clock is available.
locale string Resolved BCP 47 locale.
direction CalendarDirection Resolved text direction.
weekStartsOn Weekday Resolved first day of week.
disabled boolean Whether every control is disabled.
readOnly boolean Whether selection is blocked while navigation works.
pending boolean Whether no date is known yet: no value, focused date, today, or now was supplied, so the grid waits for the client clock after mount.
state CalendarState Stable root state token.
root HTMLDivElement | null Rendered root element.
focus (options?: FocusOptions) => boolean Focus the roving day button; returns whether focus moved.
setFocusedDate (date: PlainDate) => void Move the keyboard focus target (and visible months) to a date, clamped to min/max.
setVisibleMonth (month: PlainYearMonth) => void Show a month as the first visible month.
navigate (unit: CalendarNavigationUnit, direction: -1 | 1) => boolean Navigate by one page of months or years; returns whether the view moved.
value DateRange | null Current committed range.
anchor PlainDate | null First endpoint of a range that is still being picked, or null.
setValue (value: DateRange | null) => boolean Request a new range; returns whether it differs.
cancel () => boolean Cancel a pending anchor; returns whether one was pending.

RangeCalendarGrid

Source: src/families/date-time/calendar/calendar-grid.vue

Props

Prop Type Default Description
monthIndex number 0 Zero-based index of the visible month this grid renders.
showWeekNumbers boolean false Render a leading row header with the ISO 8601 week number of each row.
weekNumberLabel string "Wk" Visible week-number column header.
weekNumberHeader string "Week" Full week-number column header used as abbr.

Slots

Slot Slot props Description
weekday CalendarWeekdaySlotState Weekday column header content. Receives the weekday, its labels, and column index.
weekNumber CalendarWeekNumberSlotState Week-number row header content. Receives the ISO week and the row's days.
day CalendarDayState Day button content. Receives the complete day state; defaults to the localized day number.

RangeCalendarHeading

Source: src/families/date-time/calendar/calendar-heading.vue

Slots

Slot Slot props Description
default CalendarHeadingSlotState Heading content. Receives the localized heading and visible months.

RangeCalendarMonthSelect

Source: src/families/date-time/calendar/calendar-month-select.vue

Props

Prop Type Default Description
ariaLabel string "Month" Accessible name of the native select.

Events

Event Payload Description
change [month: number, nativeEvent: Event] Fired after the user picks a month, with the ISO month number.

RangeCalendarNext

Source: src/families/date-time/calendar/calendar-next.vue

Props

Prop Type Default Description
unit CalendarNavigationUnit "month" Whether the control pages by month (or numberOfMonths when paged) or by year.
ariaLabel string undefined Accessible name; defaults to "Next month" or "Next year".

Events

Event Payload Description
click [nativeEvent: MouseEvent] Fired before navigation. Call preventDefault() to keep the view unchanged.

Slots

Slot Slot props Description
default CalendarNavigationSlotState Control content. Receives the unit and whether navigation is possible.

RangeCalendarPrev

Source: src/families/date-time/calendar/calendar-prev.vue

Props

Prop Type Default Description
unit CalendarNavigationUnit "month" Whether the control pages by month (or numberOfMonths when paged) or by year.
ariaLabel string undefined Accessible name; defaults to "Previous month" or "Previous year".

Events

Event Payload Description
click [nativeEvent: MouseEvent] Fired before navigation. Call preventDefault() to keep the view unchanged.

Slots

Slot Slot props Description
default CalendarNavigationSlotState Control content. Receives the unit and whether navigation is possible.

RangeCalendarYearSelect

Source: src/families/date-time/calendar/calendar-year-select.vue

Props

Prop Type Default Description
from number undefined First listed year; defaults to the min year or ten years before the view.
to number undefined Last listed year; defaults to the max year or ten years after the view.
ariaLabel string "Year" Accessible name of the native select.

Events

Event Payload Description
change [year: number, nativeEvent: Event] Fired after the user picks a year.

Behavior

Normative state x input -> outcome table for range-calendar-root.vue (@vizejs/ui/range-calendar). The root publishes the same context as CalendarRoot, so calendar-grid.vue, calendar-heading.vue, calendar-prev.vue, calendar-next.vue, and the month/year selects are reused as RangeCalendar* parts; keyboard, locale, bounds, and SSR rules from calendar.behavior.md apply unchanged. Every row is proven by the named test.

# State Input Outcome Proven by
R1 empty first activation the date becomes the anchor (data-anchor, anchor-change); grids are aria-multiselectable two activations anchor, preview, and commit an ordered range
R2 anchored pointer enter the preview range is marked with data-in-range, data-range-start, data-range-end, and data-preview; previewed middles are aria-selected="false" two activations anchor, preview, and commit an ordered range
R3 anchored second activation an ordered range commits: anchor-change(null), update:modelValue, change; middles become range-middle and aria-selected="true"; startName/endName inputs submit ISO two activations anchor, preview, and commit an ordered range
R4 anchored keyboard focus / Escape focus movement previews the range; Escape cancels the anchor and is consumed only when an anchor exists keyboard focus previews the range and Escape cancels the anchor
R5 unavailable dates completing activation a range spanning an unavailable date restarts the anchor unless allowNonContiguousRanges unavailable dates break ranges unless non-contiguous ranges are allowed
R6 controlled / read-only render / expose / activation controlled ranges render across months (outside days included); setValue, cancel, anchor are exposed; read-only blocks anchoring controlled ranges, read-only mode, and the exposed API
R7 SSR/hydration isolated requests byte-identical markup, no anchor or preview state, silent hydration renders byte-identical range markup across isolated SSR requests, hydrates a range calendar without mismatches

Props and emits beyond CalendarRoot

Surface Contract
modelValue / defaultValue DateRange | null; ranges are normalized so start <= end.
allowNonContiguousRanges Permit committed ranges that include unavailable dates. Default false.
startName / endName Hidden inputs submitting the ISO endpoints.
anchor-change(anchor) Fires when the first endpoint is picked, cancelled, or completed.
select(range, event) Fires for every completed selection, even when unchanged.
root data data-mode="range", data-start, data-end, data-anchor.