calendar-tsx

Primitives and providers

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

useCalendar

const calendar = useCalendar(() => options);

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

  • The instance is created once, from the options read untracked.
  • It mounts with the owner, which starts the clock, and unmounts on cleanup.
  • A render effect passes options() through ~update, and reruns whenever a signal read inside the accessor changes. The state re-derives only when a tracked option changed, so keep views, features, events and resources referentially stable.

Read signals inside the accessor (view: view()), not outside it, or changes won't reach the calendar.

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);
const preview = () => bindings.preview();

Requires interaction and pointer features. Returns callback refs for root, surface(descriptor) and source(key, descriptor), an operation(key, descriptor) ref for custom operations, cancel(), and a reactive preview accessor. Read preview() inside reactive rendering. The hook mounts browser listeners with the owner and releases them on cleanup. Display-only calendars do not call this hook.

See selection and event editing for setup, source refs and preview rendering.

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 as props, and re-syncs when they change. Use it when nothing outside the tree needs the instance.

export const Embedded = () => {
  const [view, setView] = createSignal<ViewKey>('agenda');
  const [date, setDate] = createSignal(Temporal.Now.plainDateISO());

  return (
    <Calendar
      timeZone={timeZone}
      views={views}
      features={features}
      view={view()}
      date={date()}
      events={bookings}
      onNavigate={next => {
        setView(next.view);
        setDate(next.date);
      }}
      locale='en-GB'
    >
      <Count />
    </Calendar>
  );
};

useCalendarSelector

Selects from the calendar's state in context, and returns an accessor that updates when the selected value changes.

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

const Count = () => {
  // an accessor; it updates when the selected value changes
  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>;
};

Narrowing the layout

<Show> narrows a value, not a discriminated union, so derive an accessor that is the layout only when it has the kind you render. The view examples use this helper:

layouts.ts
type Layout = State['layout'];

/** The current layout when it is of `kind`, for `<Show when={…}>`. */
export const useLayout = <TKind extends Layout['kind']>(kind: TKind) => {
  const layout = useCalendarSelector((state: State) => state.layout);

  return () => {
    const current = layout();

    return current.kind === kind ? (current as Extract<Layout, { kind: TKind }>) : undefined;
  };
};

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. It returns add, update, remove and reset, plus events, an accessor for the current list. Read it inside the useCalendar accessor.