Skip to content

Calendar

Calendar is a focusable month-grid view for selecting a day. It shows one month at a time — a header, a weekday row, and a 6×7 day grid — and lets the user move a day cursor and commit a day. Selection is a two-way Signal<CalendarDate | null> (null = nothing selected), where a CalendarDate is a plain { year, month, day } civil date (helpers: daysInMonth, dayOfWeek, addMonths, addDays, compare, toISO, parseISO, fromDate, toDate).

Usage

ts
import { Calendar, signal } from '@jsvision/ui';
import type { CalendarDate } from '@jsvision/ui';

const value = signal<CalendarDate | null>({ year: 2026, month: 9, day: 14 });
const cal = new Calendar({
  value,
  today: { year: 2026, month: 7, day: 10 }, // pass it for deterministic tests
  density: 'comfortable',
  onChange: (d) => console.log('picked', d),
});
cal.layout = { position: 'absolute', rect: { x: 0, y: 0, width: 28, height: 10 } };
// Arrows move the cursor; Enter/Space commit; T jumps to today.

Live example

🚧 Live demo coming soon

An interactive, in-browser demo of Calendar lands in a later update. Until then, the reference below covers its full API.

Props

new Calendar(options).

PropTypeDefaultDescription
valueSignal<CalendarDate | null>Two-way selected day (null = none).
todayCalendarDatesystem clockThe day highlighted as "today"; pass it for reproducible tests.
minCalendarDateInclusive lower bound — the cursor never leaves [min, max].
maxCalendarDateInclusive upper bound.
isDisabled(date: CalendarDate) => booleanDims a day: navigable but not committable.
firstDayOfWeek0 | 10 (Sunday)1 = Monday (ISO).
showWeekNumbersbooleanfalseLeading ISO week-number column (adds 3 columns).
density'compact' | 'comfortable' | 'spacious''comfortable'Trades screen space for roominess (see Sizing).
onChange(date: CalendarDate) => voidFired when value changes.

Keyboard & mouse

InputResult
← / → / ↑ / ↓Move the cursor one day / one week.
PgUp / PgDnChange the month.
Ctrl+PgUp / PgDnChange the year.
Home / EndJump to the start / end of the cursor's week.
+ / −Page the visible month without moving the cursor.
TJump to today.
Enter / SpaceCommit the cursor's day.
Click a dayMove the cursor there and commit it.
Header ↑↓ arrowsChange the visible month (left pair) / year (right pair).
Footer Today buttonJump to and select today (comfortable / spacious).

Sizing & layout

Density sets the footprint: 'compact' ≈ 20×8 (tightest), 'comfortable' ≈ 28×10 (4-wide cells + a Today footer, the default), 'spacious' ≈ 35×15 (5-wide cells + blank week spacers). Use the widget's measure() to size it to the chosen density; enabling showWeekNumbers adds 3 columns.

Best practices

  • Pass today in tests. It defaults to the system clock at construction — supply it explicitly so golden output stays stable.
  • Bound with min/max. They clamp both the cursor and the visible month, so the user can't navigate out of the allowed range.
  • Disable, don't remove. An isDisabled day stays visible and navigable but can't be committed — clearer than hiding it.

Theming

RoleApplies to
calendarNormalA normal day: yellow on cyan
calendarTodayThe "today" day: blue on green
calendarSelectedThe selected day: filled blue
calendarCursorThe focused cursor cell: reverse black-on-white
calendarDisabledA dimmed, non-committable day
calendarWeekNumberThe ISO week-number column