API
useCalendar
A memoized projection of buildCalendar that hands errors back instead of throwing them.
Signature
useCalendar(range, events) is a memoized projection of buildCalendar. It holds no state and runs no effects, so the range stays yours.
import type { CalendarRange, CalendarResult, EventInput, } from '@midstem/chronous-react' export declare function useCalendar<TData>( range: CalendarRange, events: readonly EventInput<TData>[], ): CalendarResult<TData>
type CalendarResult<TData = unknown> = | { calendar: CalendarLayout<TData>; error: null } | { calendar: null; error: CalendarError }
| Field | Type | Description |
|---|---|---|
calendar | CalendarLayout<TData> | null | The layout to render. Null exactly when an error is set. |
error | CalendarError | null | An InvalidEventError, InvalidRangeError, InvalidRecurrenceError or MissingTemporalError caught during the build. |
Errors come back, not out
buildCalendar throws on the first unusable event, on an unreadable range and on a recurrence rule it cannot read — and a throw during render takes the whole tree down. The hook catches InvalidEventError, InvalidRangeError and InvalidRecurrenceError and hands them back instead: calendar is null exactly when error is set. Anything else is a bug and is left to propagate.
import { useCalendar } from '@midstem/chronous-react' import type { CalendarRange, EventInput } from '@midstem/chronous-react' const range: CalendarRange = { view: 'week', currentDate: '2026-03-18', timeZone: 'Europe/Kyiv', } const events: EventInput[] = [ { id: 'standup', start: '2026-03-18T09:00', duration: 'PT30M' }, ] export const Board = () => { const { calendar, error } = useCalendar(range, events) if (error) return <p>{error.message}</p> if (!calendar) return null return <p>{calendar.days.length} days drawn</p> }
Memoization
The memo is keyed on the fields of the range rather than on its identity, so an inline object literal does not rebuild the calendar on every render. Events are keyed by reference — memoize that array yourself if it is built inline.
import { useCalendar } from '@midstem/chronous-react' import type { EventInput } from '@midstem/chronous-react' import { useMemo } from 'react' type Meeting = { id: string; at: string; minutes: number } const toEvent = (meeting: Meeting): EventInput => ({ id: meeting.id, start: meeting.at, duration: `PT${meeting.minutes}M`, }) export const Board = ({ currentDate, timeZone, meetings, }: { currentDate: string timeZone: string meetings: Meeting[] }) => { // Events are keyed by reference, so an array built inline is memoized. const events = useMemo(() => meetings.map(toEvent), [meetings]) // The range is keyed on its fields, so an object literal is fine as it is. const { calendar } = useCalendar({ view: 'week', currentDate, timeZone }, events) return <p>{calendar?.days.length ?? 0} days drawn</p> }