calendar-tsx

Hooks and providers

Calendar setup, context, selectors, event stores and interaction bindings.

useCalendar

const calendar = useCalendar(options);

Takes the options and returns the instance. Set accessible-label locale on CalendarProvider or Calendar; it is rejected in hook options.

  • The instance is created on the first render and kept for the component's lifetime.
  • It mounts in a layout effect, which starts the clock, and unmounts with the component.
  • Every render passes the current options through ~update. The state re-derives only when a tracked option changed, so keep views, features, events and resources referentially stable between renders.

Let the types infer

Don't pass type arguments such as useCalendar<Booking>(…): TypeScript then stops inferring the rest, and view and onNavigate widen to string. Type events instead, for example as Calendar_EventInput<Booking>[].

useCalendarInteractionBindings

const bindings = useCalendarInteractionBindings(calendar);

Requires interaction and pointer features. Returns stable callback refs for root, surface(descriptor) and source(key, descriptor), an operation(key, descriptor) ref for custom operations, cancel(), and the derived preview value. The hook mounts browser listeners and cleans them up on unmount. Registration alone does not attach listeners; display-only calendars do not call this hook.

Render preview as a separate overlay and read rejection reasons from calendar.api.interactions.store. See selection and event editing for typed setup and rendering examples.

CalendarProvider

<CalendarProvider value={calendar} locale='en-GB'>
  {children}
</CalendarProvider>

Puts an instance in context for the parts and useCalendarSelector. Every part must render inside a CalendarProvider or Calendar, or it throws.

PropTypeDefaultDescription
valueThe calendar instancerequiredUsually from useCalendar.
localestring'en-US'Locale for the parts' default accessible labels.

Calendar

useCalendar and CalendarProvider in one component: it takes the core options plus locale and children. Use it when nothing outside the tree needs the instance.

export const Embedded = () => (
  <Calendar
    timeZone={timeZone}
    views={views}
    features={features}
    view='agenda'
    date={Temporal.Now.plainDateISO()}
    events={bookings}
    onNavigate={() => {}}
    locale='en-GB'
  >
    <Count />
  </Calendar>
);

useCalendarSelector

Selects from the calendar's state in context, and re-renders when the selected value changes by ===.

The context cannot carry the instance's types, so the state defaults to the widest type: every layout kind, and events with data: unknown. Annotate the selector's parameter with Calendar_StateOf<typeof calendar>, or build the type from your views with Calendar_State.

const Count = () => {
  // select the smallest slice you need; a new object from the selector re-renders on every change
  const count = useCalendarSelector((state: State) =>
    state.layout.kind === 'list' ? state.layout.days.reduce((sum, day) => sum + day.events.length, 0) : 0,
  );

  return <p>{count} events this week</p>;
};

useCalendarContext

Returns { instance, locale } from the nearest provider, with the instance's types erased. Parts use it; you rarely need it.

useCalendarEventStore

The event store, created once per component. It returns add, update, remove and reset, plus events, the current list, which re-renders the component when it changes.