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 keepviews,features,eventsandresourcesreferentially 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.
| Prop | Type | Default | Description |
|---|---|---|---|
value | The calendar instance | required | Usually from useCalendar. |
locale | string | '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:
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.