Date and time

Range Calendar

A month grid for picking a date range.

Rust
1use herogpui::components::range_calendar::RangeCalendar;

Usage

An Indian-calendar range aligned to the end of a two-month view. The January 21-22 Gregorian selection stays in the second displayed month.

Rust
1use herogpui::prelude::{Date, RangeCalendar, SelectionAlignment, VisibleDuration};
2
3RangeCalendar::new(self.demo_range("rc-indian", cx))
4    .locale("en-US-u-ca-indian")
5    .default_value((Date::new(2026, 1, 21), Date::new(2026, 1, 22)))
6    .visible_duration(VisibleDuration::Months(2))
7    .selection_alignment(SelectionAlignment::End)

Live HeroGPUI compiled to WebAssembly. Select any example without loading another WASM instance.

Anatomy

Rust types

RangeCalendar

Range Calendar is assembled from these builders. The API reference lists each one.

Customization

Appearance builders and theme tokens Range Calendar uses.

Styling

Range Calendar styling
StyleDescription
CALENDAR_WIDTH 252px / multiple-month column 256pxSingle-month, week and day roots use 252px; multiple months use the documented 256px panels, 32px gaps and horizontal scrolling. GPUI has no container-query context.
VisibleDuration week/day branchesDay rows start at the week boundary, disable leading dates and pad the visible end with blank cells.
items_center + justify_between + px(2px) + pb(16px)Header alignment, 2px horizontal inset and 16px bottom padding match.
text_size(14px) + line_height(20px) + MEDIUMMonth headings use 14px/20px medium text independent of the host line height.
24px + small_radius + hover + focus ringGeometry, hover, disabled and focus exist; press and property interpolation are incomplete.
svg size(16px)Size matches; direction-aware rotation is unavailable.
seven flex_1 cells per rowSeven equal flex columns fill each panel, including the wider multiple-month layout.
weekday_header + month_grid flex columnsSeven-column flex rows start 4px below the weekday block; each range cell retains its 2px vertical margins.
text_size(12px) + line_height(16px) + MEDIUM + muted + pb(8px)Weekday labels use 12px/16px medium muted text with 8px bottom padding.
flex_1 range segment + cell_size height + row gap(4px) + grid py(2px)Each range segment spans one seventh of the panel width and contains a separate square day button; 4px row gaps reproduce the spacing between cells.
cell_size = column_width / 7 + text_size(14px) + line_height(20px) + MEDIUMThe inner day button centers 14px/20px medium text, including selected endpoints and custom cell content.
anim::pressed instantaneous geometryThe 0.9 target is exact, but the scale lands on a frame.
in_range square accent soft fillTrack fill exists; CSS sibling-aware row caps are simplified.
draw_start/draw_end rounded_full accentEndpoint accents exist as pills rather than directional half-caps joined to the track.
is_today border_1Uses an outline rather than the soft fill.
PRESSED_SCALE_RANGE + default active fillScale geometry matches; interpolation and endpoint accent-hover do not.
muted + outer opacity(0.5)The whole custom-content subtree is dimmed.
unavailable muted + selectable gatePointer inertia matches; muted text approximates the status utility.
disabled + line_throughIn-month line-through and outside exception match; cursor styling is not exposed.
bottom(2px) + size(3px)Size and selection color match; the inset is 2px rather than 4px.
gap(4px) + key_radius + paddingComposed and focusable, with extra padding and hover fill.
CHEVRON_UP / CHEVRON_DOWNSwaps up/down glyphs without rotation interpolation.
absolute inset_0 + retained day layout + ScrollHandle + three-cell rows + gap(4px) + p(4px)The scrollable three-column year grid occupies the retained day area; opening and keyboard movement reveal the active row.
32px + px(10px) + control radius + text_size(14px) + line_height(20px) + MEDIUMGeometry and core states exist; transitions are absent.

API reference

Builders

Range Calendar builders
BuilderTypeDefaultDescription
value(start, end, cx)start, end, cxControlled selected range written through the bound state entity.
default_value((start, end))(start, end)Seeds the uncontrolled range once.
on_change(callback)Fn(value: RangeValue<DateValue>) -> ()Reports only completed ranges; the pending first endpoint remains internal anchor state.
focused_value(Date)DateControls the constrained focus date and realigns the visible range; movement waits for owner acceptance.
on_focus_change(callback)Fn(value: DateValue) -> ()Reports pointer, hover and keyboard focus movement.
min_value(Date)DateCalendar-aware 1900-01-01Defaults to Gregorian 1900-01-01; an explicit minimum overrides it.
max_value(Date)DateCalendar-aware 2099-12-31Defaults to Gregorian 2099-12-31; an explicit maximum overrides it.
weeks_in_month(usize)usizeUses the exact nonzero row count; zero falls back to the derived count.
is_date_unavailable(callback)Fn(date: DateValue, anchorDate: CalendarDate | null) -> boolReceives the active anchor for cells and both input paths; contiguous selection scans through one visible duration on each side plus the sentinel day beyond each limit, then merges discovered bounds into cells, focus and navigation.
first_day_of_week(Weekday)WeekdayLocale defaultDefaults from the operating system's regional date preferences through CLDR week data; an explicit weekday overrides it, with Sunday as the invalid-locale fallback.
page_behavior(PageBehavior)PageBehaviorPageBehavior::VisiblePages by the visible range or one displayed unit.
selection_alignment(SelectionAlignment)SelectionAlignmentSelectionAlignment::CenterExplicit alignment wins; otherwise a range extending beyond the centered window automatically starts at the first visible unit. The first pick preserves that aligned view.
allows_non_contiguous_ranges(bool)boolfalseAllows a completed range to span unavailable interior dates.
is_disabled(bool)boolfalseDisables navigation, focus and selection and dims the calendar.
is_read_only(bool)boolfalseKeeps focus and navigation while preventing range changes.
is_invalid(bool)boolfalseApplies danger accents, without v3's automatic invalid-range and validation surface.
visible_duration(VisibleDuration)VisibleDuration{months: 1}Selects month, week or day view and its visible count.
default_year_picker_open(bool)boolfalseSeeds the uncontrolled year picker open state.
is_year_picker_open(bool)boolControls the internal year picker open state.
on_year_picker_open_change(callback)Fn(isOpen: bool) -> ()Reports internal year picker changes.
offset(i32)i32Shifts all visible headings globally rather than configuring one composed heading.
visible_years(usize)usizemin-max span or 20Controls the bounded year window; otherwise the implicit 1900–2099 span is shown.
cell(render)stringHands custom content a numeric day label rather than a locale-formatted string.

Parts

Range Calendar parts
PartDescription
RangeCalendarRoot range state, layout and keyboard owner.
RangeCalendarNavigation and visible-range heading row.
RangeCalendarHeading for one visible month or linear range.
RangeCalendarPrevious and next visible-section controls.
RangeCalendarOne seven-column month, week or day grid.
RangeCalendarWeekday header container.
RangeCalendarVisible date-row container.
RangeCalendarOne weekday label.
RangeCalendarFocusable date cell and range-track segment with custom render state.
RangeCalendarOptional three-pixel metadata dot.
RangeCalendarHeading control that toggles year-picker mode.
RangeCalendarHeading content inside the year trigger.
RangeCalendarYear picker open-state chevron.
RangeCalendarScrollable three-column year surface overlaying the retained day area.
RangeCalendarMaps the year window into three-cell rows.
RangeCalendarFocusable year option returning to the day grid.

States

Range Calendar states
BuilderStateDescription
eligible range membership + accent soft fillSelected rangeDraws the selectable soft range track.
eligible interior range membershipRange middleThe docs name a distinct middle state, but the dependency does not emit its attribute; derives interior membership directly.
is_selection_start accent pillSelection startDraws the accent leading cap.
is_selection_end accent pillSelection endDraws the accent trailing cap.
is_today borderTodayUses an accent-soft fill; uses an accent outline.
is_unavailable + selectable gateUnavailableFocusable but pointer-inert date with disabled styling.
outside_month + opacity(0.5)Outside monthReal adjacent-month date, disabled and unselected at half opacity.
on_hover + cursor + default fillHoveredMoves anchored focus and previews the same range Enter will commit, but today lacks v3's accent-soft-hover fill.
anim::pressed + PRESSED_SCALE_RANGEPressedUses the exact 0.9 geometry, but without v3's 200ms scale interpolation.
grid_focus + with_focus_ringFocus visibleRoving in-month focus ring shared by hover and keyboard. Month boundaries, paging, alignment and year selection follow the chosen calendar system while focus values stay Gregorian.
is_disabled / out_of_rangeDisabledInert calendar or date with disabled opacity and in-month line-through.
is_read_only + selectable gateRead onlyRetains focus and navigation without selection changes.
year_picker_open overlay + invisible day bodyYear picker openThe scrollable year grid overlays the retained day layout, without the staggered crossfade.