Skip to main content

The event type

Events are plain objects. The only required fields are start, end, and title; everything else is yours. CalendarEvent<T> is generic, so you can attach your own fields and read them back in callbacks and renderers.
  • allDay lays the event out in the all-day lane above the grid instead of in the columns. It’s also inferred for midnight-to-midnight spans. Pass showAllDayEventCell={false} to hide the lane entirely (its events won’t show). In the schedule view (which has no lane) an all-day event reads “All day” instead of a time range; override the wording with allDayLabel (e.g. for a different language).
  • disabled opts an event out of drag interactions.
  • draggable, startEditable, and durationEditable control per-event drag and resize (see the drag guide).
  • dragHandleColor overrides the resize grip colour for an event in the native time grid and resource timeline. It defaults to theme.colors.eventText.
  • Multi-day events draw as one continuous bar across the days they span in the month view, and as a per-day clipped segment on the week/day time grid.

Render your own event

For Solid, use the custom event example. For React DOM, see the web renderer guide. Both web Calendar components use separate renderers for timed, month, and schedule events. On React Native, pass renderEvent, a component that receives RenderEventArgs. It’s used in every mode and for every event shape (timed, all-day, multi-day), so you only write it once.
Wrapping events in a portaling overlay (a context menu, popover) on the web? Portal it into your app’s React root, not document.body — see the Web guide.
On the day/week grid a timed event’s box is sized to its duration and given to your renderer as boxHeight, so it tracks the grid’s hour scale as the grid zooms or resizes. Fit your content to boxHeight: the built-in renderer clamps its own content, and a custom renderer should adapt (show less, or scroll) rather than assume a fixed size, since content taller than the slot is clipped. boxHeight never drops below the grid’s minEventHeight (default 32 on native, 14 on the dom renderer); set it to 0 if your renderer should get the exact duration height. The box is inset from its slot by eventGap (see Event boxes).

Lighter touches

If you only want to tweak the built-in event box, you don’t need a full renderEvent:
  • eventCellStyle — a style (or a function of the event) merged onto the built-in box.
  • keyExtractor — a stable key per event; defaults to start-time + index.
  • showTime shows the time range under the title (default true). The title comes first: on the day/week grid it fills the box with as many whole lines as fit (never a half-cut line), and the time only appears once a full line is free beneath it.
  • ellipsizeTitle ends a single-line title (the all-day lane, month cells) with a trailing ellipsis when it overflows, instead of a hard clip (default false).

Screen-reader labels

Each event announces a built-in label: its title plus the time range (or “all day”), which the grid otherwise only shows visually. Override it per event with eventAccessibilityLabel. It receives the event and a { mode, isAllDay, ampm } context, and its return value replaces the default label across every view.
The same prop is on the standalone MonthView, MonthList, and TimeGrid, so a custom renderer and its label stay in sync.

Background events

Set display: "background" to paint an event’s time range as a shaded, non-interactive band behind the grid instead of an event box — blocked time, maintenance windows, public holidays:
Background events shade the time grid and the resource timeline’s lanes (an all-day or multi-day one covers each day’s full window). They take no overlap column, render no chip in the month grid or agenda, and produce no year-view dot. Restyle the band with the backgroundEvent slot or the theme’s backgroundEvent colour token. To draw a band yourself, or make it pressable, pass a component as renderBackgroundEvent to Calendar or TimeGrid on either renderer (the resource timeline keeps the shade). It is rendered like renderEvent, so it may use hooks, and receives the event, the mode, the band’s boxHeight, the ampm flag, continuesBefore / continuesAfter for a multi-day event, and onPress, which fires onPressEvent; React Native adds onLongPress and makes boxHeight a live shared value that follows a pinch. The themed tint is dropped, the band lets touches or pointer events through to what you render, and it is no longer hidden from assistive tech. On the web the band itself takes no focus, so render a focusable control such as a button for keyboard users. Cell presses and drag-to-create are unreachable underneath such a band. Define the component outside your render so it keeps its identity (on the web the args type is DomRenderEventArgs from @super-calendar/dom):

Loading events from a feed

useEventSource (from @super-calendar/core) owns the fetching for you: point it at a JSON feed, an iCalendar feed (.ics URLs are parsed automatically), or your own async function, and hand the result to any view. Set refetchIntervalMs for a live feed; refetch reloads on demand, and a failed refetch keeps the previous events while reporting error.
JSON feeds default to items with ISO start/end strings; pass map to reshape anything else (rename fields, attach a resourceId, filter). The default mapper validates calendar fields and revives recurrence until, exdates, and rdates. Invalid data rejects the batch and sets error, keeping the previous events. A custom map receives an array of unknown items and owns their validation and conversion. Extra event fields are preserved. Polling requires a finite refetchIntervalMs greater than zero and no larger than 2147483647 (the timer limit, about 24.8 days). Other values disable it. Unmounting stops polling and aborts pending URL requests. Retained refetch callbacks do nothing after unmount. One nuance for function sources: swapping the function itself doesn’t trigger a refetch (inline functions change identity every render, which would loop). The next interval tick or a manual refetch() always calls the latest function, so change what the function reads, or call refetch() after swapping it. In Solid, use createEventSource. Its source and options are accessors, and changes to either trigger a reload, including a new async function. For one batch without a reactive owner, import loadEventSource from @super-calendar/core/vanilla or @super-calendar/core:
The loader accepts source, format, map, and an optional signal. It does not poll or retain state. HTTP failures, malformed JSON feeds, and cancellation reject its promise. The abort signal applies to URL requests; custom async functions manage their own cancellation.