ChronousDocumentation

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.

tsx
import type {
  CalendarRange,
  CalendarResult,
  EventInput,
} from '@midstem/chronous-react'

export declare function useCalendar<TData>(
  range: CalendarRange,
  events: readonly EventInput<TData>[],
): CalendarResult<TData>
Result
type CalendarResult<TData = unknown> =
  | { calendar: CalendarLayout<TData>; error: null }
  | { calendar: null; error: CalendarError }
FieldTypeDescription
calendarCalendarLayout<TData> | nullThe layout to render. Null exactly when an error is set.
errorCalendarError | nullAn 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.

tsx
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.

tsx
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>
}