Range Calendar
A month grid for picking a date range.
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.
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
| Style | Description |
|---|---|
CALENDAR_WIDTH 252px / multiple-month column 256px | Single-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 branches | Day 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) + MEDIUM | Month headings use 14px/20px medium text independent of the host line height. |
24px + small_radius + hover + focus ring | Geometry, 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 row | Seven equal flex columns fill each panel, including the wider multiple-month layout. |
weekday_header + month_grid flex columns | Seven-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) + MEDIUM | The inner day button centers 14px/20px medium text, including selected endpoints and custom cell content. |
anim::pressed instantaneous geometry | The 0.9 target is exact, but the scale lands on a frame. |
in_range square accent soft fill | Track fill exists; CSS sibling-aware row caps are simplified. |
draw_start/draw_end rounded_full accent | Endpoint accents exist as pills rather than directional half-caps joined to the track. |
is_today border_1 | Uses an outline rather than the soft fill. |
PRESSED_SCALE_RANGE + default active fill | Scale geometry matches; interpolation and endpoint accent-hover do not. |
muted + outer opacity(0.5) | The whole custom-content subtree is dimmed. |
unavailable muted + selectable gate | Pointer inertia matches; muted text approximates the status utility. |
disabled + line_through | In-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 + padding | Composed and focusable, with extra padding and hover fill. |
CHEVRON_UP / CHEVRON_DOWN | Swaps 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) + MEDIUM | Geometry and core states exist; transitions are absent. |
API reference
Builders
| Builder | Type | Default | Description |
|---|---|---|---|
value( | start, | — | Controlled selected range written through the bound state entity. |
default_value( | ( | — | Seeds the uncontrolled range once. |
on_change( | Fn( | — | Reports only completed ranges; the pending first endpoint remains internal anchor state. |
focused_value( | Date | — | Controls the constrained focus date and realigns the visible range; movement waits for owner acceptance. |
on_focus_change( | Fn( | — | Reports pointer, hover and keyboard focus movement. |
min_value( | Date | Calendar-aware 1900-01-01 | Defaults to Gregorian 1900-01-01; an explicit minimum overrides it. |
max_value( | Date | Calendar-aware 2099-12-31 | Defaults to Gregorian 2099-12-31; an explicit maximum overrides it. |
weeks_in_month( | usize | — | Uses the exact nonzero row count; zero falls back to the derived count. |
is_date_unavailable( | Fn( | — | Receives 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 | Locale default | Defaults 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 | PageBehavior:: | Pages by the visible range or one displayed unit. |
selection_alignment( | SelectionAlignment | SelectionAlignment:: | Explicit 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 | false | Allows a completed range to span unavailable interior dates. |
is_disabled( | bool | false | Disables navigation, focus and selection and dims the calendar. |
is_read_only( | bool | false | Keeps focus and navigation while preventing range changes. |
is_invalid( | bool | false | Applies danger accents, without v3's automatic invalid-range and validation surface. |
visible_duration( | VisibleDuration | {months: 1} | Selects month, week or day view and its visible count. |
default_year_picker_open( | bool | false | Seeds the uncontrolled year picker open state. |
is_year_picker_open( | bool | — | Controls the internal year picker open state. |
on_year_picker_open_change( | Fn( | — | Reports internal year picker changes. |
offset( | i32 | — | Shifts all visible headings globally rather than configuring one composed heading. |
visible_years( | usize | min-max span or 20 | Controls the bounded year window; otherwise the implicit 1900–2099 span is shown. |
cell( | string | — | Hands custom content a numeric day label rather than a locale-formatted string. |
Parts
| Part | Description |
|---|---|
RangeCalendar | Root range state, layout and keyboard owner. |
RangeCalendar | Navigation and visible-range heading row. |
RangeCalendar | Heading for one visible month or linear range. |
RangeCalendar | Previous and next visible-section controls. |
RangeCalendar | One seven-column month, week or day grid. |
RangeCalendar | Weekday header container. |
RangeCalendar | Visible date-row container. |
RangeCalendar | One weekday label. |
RangeCalendar | Focusable date cell and range-track segment with custom render state. |
RangeCalendar | Optional three-pixel metadata dot. |
RangeCalendar | Heading control that toggles year-picker mode. |
RangeCalendar | Heading content inside the year trigger. |
RangeCalendar | Year picker open-state chevron. |
RangeCalendar | Scrollable three-column year surface overlaying the retained day area. |
RangeCalendar | Maps the year window into three-cell rows. |
RangeCalendar | Focusable year option returning to the day grid. |
States
| Builder | State | Description |
|---|---|---|
eligible range membership + accent soft fill | Selected range | Draws the selectable soft range track. |
eligible interior range membership | Range middle | The docs name a distinct middle state, but the dependency does not emit its attribute; derives interior membership directly. |
is_selection_start accent pill | Selection start | Draws the accent leading cap. |
is_selection_end accent pill | Selection end | Draws the accent trailing cap. |
is_today border | Today | Uses an accent-soft fill; uses an accent outline. |
is_unavailable + selectable gate | Unavailable | Focusable but pointer-inert date with disabled styling. |
outside_month + opacity(0.5) | Outside month | Real adjacent-month date, disabled and unselected at half opacity. |
on_hover + cursor + default fill | Hovered | Moves anchored focus and previews the same range Enter will commit, but today lacks v3's accent-soft-hover fill. |
anim::pressed + PRESSED_SCALE_RANGE | Pressed | Uses the exact 0.9 geometry, but without v3's 200ms scale interpolation. |
grid_focus + with_focus_ring | Focus visible | Roving 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_range | Disabled | Inert calendar or date with disabled opacity and in-month line-through. |
is_read_only + selectable gate | Read only | Retains focus and navigation without selection changes. |
year_picker_open overlay + invisible day body | Year picker open | The scrollable year grid overlays the retained day layout, without the staggered crossfade. |