[ @sdxc/ui/behaviors ]
CalendarModel
Headless state model for calendar grids.
import { CalendarModel } from "@sdxc/ui/behaviors";Usage
Owns the ephemeral state around picking a date: the keyboard-focused day,
the visible month page, and a range's anchor plus hover preview. The chosen
value stays with the consumer, and every state change dispatches "change".
Signature
new CalendarModel(options?: CalendarModel.Options)Parameters
| Parameter | Type | Description |
|---|---|---|
options? | CalendarModel.Options | Initial focus, selectable bounds, and disabled-day rule. |
Properties
| Property | Type | Description |
|---|---|---|
focusedDate | Date | The day that currently carries keyboard/roving-tabindex focus. Always a fresh Date instance, so callers may mutate it freely. |
visibleMonth | Date | The first day of the month page on screen. Follows focus into a new month, and moves on its own when the consumer pages the grid via showMonth/showNextMonth/showPreviousMonth. |
anchorDate | Date | null | The first day picked while building a range, or null when no range selection is in progress. |
previewDate | Date | null | The day currently under hover/focus while a range's second endpoint is being chosen, or null when there is no pending range or no day has been previewed yet. |
previewRange | CalendarModel.Range | null | The range implied by the current anchor and preview day, normalized so start comes first; null when no range selection is in progress. Before a preview day is set it collapses to a single day on the anchor. |
min | Date | null | Earliest day the model accepts, or null when unbounded. |
max | Date | null | Latest day the model accepts, or null when unbounded. |
Methods
| Method | Description |
|---|---|
focusDate(date: Date): void | Moves focus to an arbitrary day, clamped to the selectable bounds, and pages the visible month to match. Suits pointer selection of a grid cell; the directional focus* methods own the keyboard offset math. |
focusNextDay(): void | Moves focus one day forward (typically the ArrowRight key). |
focusPreviousDay(): void | Moves focus one day back (typically the ArrowLeft key). |
focusNextWeek(): void | Moves focus one week forward (typically the ArrowDown key). |
focusPreviousWeek(): void | Moves focus one week back (typically the ArrowUp key). |
focusNextMonth(): void | Moves focus one month forward, clamping the day of month to the target month's last day when it's shorter (typically the PageDown key). |
focusPreviousMonth(): void | Moves focus one month back, clamping the day of month to the target month's last day when it's shorter (typically the PageUp key). |
focusMonthStart(): void | Moves focus to the first day of the focused month (typically the Home key). |
focusMonthEnd(): void | Moves focus to the last day of the focused month (typically the End key). |
showMonth(date: Date): void | Pages the visible month to the month containing date, leaving focus where it is — the focused day scrolls out of the rendered grid until focus moves again. Suits a header's month/year picker. |
showNextMonth(): void | Pages the visible month forward by one, leaving focus where it is. |
showPreviousMonth(): void | Pages the visible month back by one, leaving focus where it is. |
beginRange(date: Date): void | Starts a range selection at date, clearing any preview from a previous attempt. Call this when the user picks the first endpoint (e.g. the first click in a range calendar). |
updateRangePreview(date: Date): void | Updates the pending second endpoint so previewRange tracks the day under hover or focus. A no-op while no range is in progress, so hover handlers can call it unconditionally. |
completeRange(date: Date): CalendarModel.Range | null | Commits the range from the current anchor to date and clears the pending selection, returning it normalized. With no range in progress the consumer's selected value stays untouched. |
cancelRange(): void | Abandons an in-progress range selection (e.g. on Escape or blur), leaving the consumer's selected value untouched. A no-op when no range is in progress. |
isFocused(date: Date): boolean | Whether date is the day currently carrying keyboard focus. |
isRangeAnchor(date: Date): boolean | Whether date is the anchor of an in-progress range selection. |
isInPreviewRange(date: Date): boolean | Whether date falls within the current previewRange, inclusive of both endpoints. Always false when no range is in progress. |
isInVisibleMonth(date: Date): boolean | Whether date falls in the same month as visibleMonth. Useful for dimming the leading/trailing days a month grid renders from adjacent months. |
isDisabled(date: Date): boolean | Whether date falls outside the selectable bounds — before min, after max, or rejected by the isDateDisabled predicate. |
Examples
let model = new CalendarModel({ focusedDate: new Date(2026, 0, 15) });
model.addEventListener("change", () => update());
model.focusNextDay();Used with it
The events, constants and types its module publishes, each imported from @sdxc/ui/behaviors too.
Interface
CalendarModel.Range
An inclusive start/end pair of calendar days, always normalized so
start comes first, whatever order the two endpoints were picked in.
| Member | Type | Description |
|---|---|---|
start | Date | |
end | Date |
Interface
CalendarModel.Options
Constructor options for CalendarModel.
| Member | Type | Description |
|---|---|---|
focusedDate? | Date | Day that starts focused. Defaults to today when omitted. Only the calendar date is read; time-of-day is discarded. |
min? | Date | Earliest day the model will focus or accept as a range endpoint; navigation and range methods clamp to it. |
max? | Date | Latest day the model will focus or accept as a range endpoint; navigation and range methods clamp to it. |
isDateDisabled? | (date: Date) => boolean | Predicate marking individual days as unselectable (closures on a weekend, already-booked slots, …). Navigation still visits these days, so keyboard users can reach a selectable day past them. |
Interface
CalendarModel.EventMap
Events dispatched by CalendarModel as its state changes.
| Member | Type | Description |
|---|---|---|
change | Event | Dispatched after focus, the visible month, the range anchor, or the range preview changes. |