GitHubGitHub
← All components
Forms / component

Range calendar

A two-click date-range grid with hover preview, a continuous selection track, and full keyboard roaming. Calendar-date math only — no timezone drift, no date library.

Single monthTwo monthsBoundedCompact
June 2026
July 2026

2026-06-08 → 2026-06-17

<RangeCalendar bind:start bind:end months={2} onchange={apply} />

Installation

pnpm add @chanrg/4ui

Import the stylesheet once, at the root of your app:

import '@chanrg/4ui/styles.css';

Usage

import { RangeCalendar } from '@chanrg/4ui';<RangeCalendar bind:start bind:end months={2} onchange={apply} />

Two months

Show two grids side by side when the range usually spans a month boundary.

June 2026
July 2026

2026-06-08 → 2026-07-02

<RangeCalendar bind:start bind:end months={2} />

Bounded

Pass min and max to clamp selection; month navigation disables at the edges.

June 2026

Selectable 2026-06-08 → 2026-06-22

<RangeCalendar bind:start bind:end min="2026-06-01" max="2026-06-30" />

Compact

Denser cells for a calendar embedded in a narrow form column.

June 2026

2026-06-08 → 2026-06-12

<RangeCalendar bind:start bind:end compact />

API reference

Props

PropTypeDefaultDescription
start / end'YYYY-MM-DD' | nullnullRange endpoints; bindable and auto-ordered low→high.
min / max'YYYY-MM-DD' | nullnullSelectable bounds; also disables month navigation past them.
months1 | 21Side-by-side grids.
weekStartsOn0 | 110 = Sunday, 1 = Monday.
localestringruntimeMonth and weekday labels.
compactbooleanfalseDenser cells for forms.
onchange({ start, end }) => voidFires once a full range is picked.

CSS variables

VariableDescription
--4ui-surfacePrimary component surface.
--4ui-textPrimary foreground color.
--4ui-borderDefault control and panel border.

Accessibility

  • The grid uses role=grid/row/gridcell with a roving tabindex; arrows move by day and week, Enter or Space picks.
  • Endpoints expose aria-selected and out-of-bounds days are disabled and aria-disabled.
  • Every cell carries a fully localized date label, so the range never depends on reading the column header.

Dependencies

Intl.DateTimeFormat