API
Calendar
Every part of the compound component, its props and the scope it hands to its children.
Calendar.Root
Everything else lives inside the root: it builds the calendar, holds the scope and renders one element of its own. The whole tree in one place:
tsx
import { createCalendarComponents } from '@midstem/chronous-react' import type { CalendarRange, EventInput } from '@midstem/chronous-react' type EventData = { title: string } // Binds your event data to every render prop — see Typed event data below. const Calendar = createCalendarComponents<EventData>() const range: CalendarRange = { view: 'week', currentDate: '2026-03-18', timeZone: 'Europe/Kyiv', } const events: EventInput<EventData>[] = [ { id: 'offsite', start: '2026-03-18', end: '2026-03-20', data: { title: 'Offsite' }, }, { id: 'standup', start: '2026-03-18T09:00', duration: 'PT30M', data: { title: 'Standup' }, }, ] export const Board = () => ( <Calendar.Root className="calendar" range={range} events={events} locale="en-GB" > <Calendar.Header className="grid-header"> <Calendar.DayHeadings className="heading"> {({ weekdayLabel, dayLabel }) => ( <> <span>{weekdayLabel}</span> <strong>{dayLabel}</strong> </> )} </Calendar.DayHeadings> </Calendar.Header> <Calendar.AllDayRow gutterCell="all-day"> <Calendar.AllDayEvents className="bar"> {({ event }) => event.data?.title} </Calendar.AllDayEvents> </Calendar.AllDayRow> <Calendar.TimeGrid hourHeight={60}> <Calendar.TimeAxis className="gutter"> <Calendar.TimeLabels className="tick" /> </Calendar.TimeAxis> <Calendar.DayColumns className="column"> <Calendar.TimeSlots className="line" /> <Calendar.NowMarker className="now" /> <Calendar.TimedEvents as="button" className="event"> {({ event }) => event.data?.title} </Calendar.TimedEvents> </Calendar.DayColumns> </Calendar.TimeGrid> </Calendar.Root> )
| Prop | Type | Default | Description |
|---|---|---|---|
range | CalendarRange | — | What to draw. Required. |
events | readonly EventInput<TData>[] | — | What to draw in it. Required. |
locale | LocaleId | 'en-US' | The locale every built-in label is formatted in. |
gutterWidth | string | '3.25rem' | The leading column shared by Header, AllDayRow and TimeGrid. Month and agenda ignore it. |
renderError | (error: CalendarError) => ReactNode | — | Rendered inside the root’s own element. Without it, an unreadable range or event rethrows. |
The time grid
Rendered for day, week and days — the views that carry slots.
| Part | Type | Description |
|---|---|---|
TimeGrid | { hourHeight, dayHeight } | The scrolling grid. Takes hourHeight (60) and scrollToHour (7), which finds the nearest element that actually scrolls; pass null to leave the scroll alone. |
TimeAxis | { hourHeight, dayHeight } | The gutter column, sized to a full day. |
TimeLabels | { slot, minuteOfDay, timeLabel } | One element per slot, positioned down the axis. |
DayColumns | { day } | One column per day, each one a positioning context. |
TimeSlots | { slot, minuteOfDay } | One element per row inside a column. |
NowMarker | { minuteOfDay } | Rendered only in the column that is today, in the calendar’s zone. Ticks every thirty seconds. |
TimedEvents | { event, box } | One element per box, already packed into its column. Takes minHeight (22) and gap (3). |
The month grid
| Part | Type | Description |
|---|---|---|
MonthGrid | { calendar, range, locale, gutterWidth } | The month container. |
MonthWeekdays | { day, weekdayLabel } | One element per weekday, read off the first row. |
MonthRows | { row, days, maxLanes, laneHeight } | One element per week. Takes maxLanes (null) and laneHeight (20), both shared with its siblings. |
MonthDays | { day, boxes, bars, hiddenBars, dayLabel, inCurrentPeriod, lanes } | One cell per day in the row. hiddenBars is what maxLanes dropped. |
MonthAllDayEvents | { event, bar } | The bars of the row, up to maxLanes. Takes gap (4) and lanesTopOffset (28). |
MonthTimedEvents | { event, box } | The timed events of one cell, in order. |
The agenda
| Part | Type | Description |
|---|---|---|
AgendaList | { calendar, range, locale, gutterWidth } | The list container. |
AgendaDays | { day, bars, boxes, weekdayLabel, dayLabel, monthLabel } | One element per day that has something in it. Takes showEmptyDays (false) to render the whole span. |
AgendaAllDayEvents | { event, bar } | The all-day entries of that day. |
AgendaTimedEvents | { event, box, timeRangeLabel } | The timed entries, with a formatted range. |
Scopes as hooks
Every scope is also a hook, so a component of your own can read it without a render prop. Reading one outside its parent throws and names the parent it wants.
| Hook | Type | Description |
|---|---|---|
useCalendarContext | { calendar, range, locale, gutterWidth } | Anywhere inside Calendar.Root. |
useTimeGridContext | { hourHeight, dayHeight } | Inside a time grid. |
useDayColumnContext | { day } | Inside a day column. |
useAllDayContext | { row, laneHeight, lanes } | Inside the all-day row. |
useMonthRowContext | { row, days, maxLanes, laneHeight } | Inside a month row. |
useMonthDayContext | { day, boxes, bars, hiddenBars } | Inside a month cell. |
useAgendaDayContext | { day, bars, boxes } | Inside an agenda day. |
useNow | (timeZone) => { date, minuteOfDay } | null | The wall clock in a zone, for marking today yourself. Null until the first client tick. |
createCalendarComponents<TData>() returns the same namespace with your event data typed on every render prop.