Range Calendar
Date range grid.
Usage
Composes exactly like Calendar; only the selection model
differs. value is { start, end } of DateValues, and @internationalized/date is a peerDependency — install it alongside sve-ui.
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
28 | 29 | 30 | 31 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
The two-step interaction
First click sets the start, second sets the end, and hovering between them previews the span. Bits also normalises a backwards selection, so clicking the end before the start does the sensible thing rather than producing an inverted range — which is the bug every hand-rolled range picker ships first.
The styling follows that model: the two endpoints are filled and the days between are a tint, with the inner corners squared off, so the span reads as one continuous band with two handles rather than as a row of separately selected days. The live hover preview uses the same tint as the committed middle, so what you see while choosing is what you get.
Bounding the span
minDays and maxDays bound how long a range may be
— a two-night minimum, a fortnight maximum.
excludeDisabled refuses a range that would straddle an unavailable date.
That one matters for booking: without it, a user can select across a day that is already taken and
the range silently swallows it. "Three nights including the one that is gone" is not a valid answer.
Props
RangeCalendar.Root
| Prop | Type | Default |
|---|---|---|
value The selected range, as `{ start, end }` of `DateValue`s from `@internationalized/date`. Bindable. | { start: DateValue | undefined; end: DateValue | undefined } | — |
onValueChange Called when the range changes. | (value: DateRange) => void | — |
placeholder The month currently on screen. Bindable. | DateValue | — |
minValue Earliest selectable date. | DateValue | — |
maxValue Latest selectable date. | DateValue | — |
minDays Smallest number of days a range may span. | number | — |
maxDays Largest number of days a range may span. | number | — |
excludeDisabled When true, a range may not straddle an unavailable date — picking one that would is rejected rather than silently swallowing the blocked day. | boolean | — |
isDateUnavailable | (date: DateValue) => boolean | — |
isDateDisabled | (date: DateValue) => boolean | — |
numberOfMonths | number | 1 |
locale BCP-47 locale driving month names, weekday order and numerals. | string | 'en' |
calendarLabel What this calendar is FOR. Bits builds the accessible name as `${calendarLabel} ${month} ${year}` and defaults it to the literal word "Event", so leave it unset and it announces "Event January 2026". | string | 'Event' |
disabled | boolean | false |
readonly | boolean | false |
class Extra classes merged onto the root. | string | — |
children | Snippet<[SnippetProps]> | — |
The shared parts are documented on the Calendar page.