Skip to Content
DocsCalendarPluginsEvent Recurrence

Event recurrence

ℹ️ Important note before getting started

This plugin enables you to create recurring events according to the iCalendar specification. Please note, however, that this plugin only offers a partial implementation of the specification. There are 2 reasons for this:

  1. Some rules just haven’t been implemented yet. If there is a rule that you would like to see implemented, please open an issue on GitHub.
  2. Some iCalendar rules are supported for display purposes but cannot be updated via drag & drop. For example, events using BYDAY with MONTHLY or YEARLY frequencies are fully supported, but cannot be updated by dragging. If you need to update such events programmatically, you can disable drag & drop for those specific events or handle updates through the events service.

If you need an almost full implementation of the iCalendar spec, you can use the rrule library instead of this plugin. Here’s an example of how to do so. However, this only works if you’re merely using the calendar to display events. If you want to use interactive features like drag & drop or resizing, you cannot use the external rrule library.

Installation

npm install @schedule-x/event-recurrence

Usage

import { createEventRecurrencePlugin } from "@schedule-x/event-recurrence"; const calendar = createCalendar({ // ... other config options plugins: [ createEventRecurrencePlugin() ], events: [ { id: 123, title: 'Bi-Weekly Event Monday and Wednesday', start: Temporal.ZonedDateTime.from('2024-02-05T14:00:00+01:00[Europe/Berlin]'), end: Temporal.ZonedDateTime.from('2024-02-05T15:00:00+01:00[Europe/Berlin]'), rrule: 'FREQ=WEEKLY;INTERVAL=2;BYDAY=MO,WE;UNTIL=20240229T235959' }, { id: 456, title: 'Weekly Event on 4 occasions', start: Temporal.PlainDate.from('2024-02-03'), end: Temporal.PlainDate.from('2024-02-03'), rrule: 'FREQ=WEEKLY;COUNT=4' }, { id: 789, title: 'Daily event 5 times', start: Temporal.ZonedDateTime.from('2024-02-05T12:00:00+01:00[Europe/Berlin]'), end: Temporal.ZonedDateTime.from('2024-02-05T13:55:00+01:00[Europe/Berlin]'), rrule: 'FREQ=DAILY;COUNT=5', calendarId: 'personal', }, { id: 121314, title: 'Daily event mo-fr 10 times', start: Temporal.ZonedDateTime.from('2024-02-05T12:00:00+01:00[Europe/Berlin]'), end: Temporal.ZonedDateTime.from('2024-02-05T13:55:00+01:00[Europe/Berlin]'), rrule: 'FREQ=DAILY;COUNT=10;BYDAY=MO,TU,WE,TH,FR', calendarId: 'work', }, { id: 141617, title: 'Monthly event on the 7th 5 times', start: Temporal.ZonedDateTime.from('2024-02-07T16:00:00+01:00[Europe/Berlin]'), end: Temporal.ZonedDateTime.from('2024-02-07T17:55:00+01:00[Europe/Berlin]'), rrule: 'FREQ=MONTHLY;COUNT=5', }, { id: 151618, title: 'Monthly event on the 1st Monday 12 times', start: Temporal.ZonedDateTime.from('2024-08-05T04:00:00+01:00[Europe/Berlin]'), end: Temporal.ZonedDateTime.from('2024-08-05T06:00:00+01:00[Europe/Berlin]'), rrule: 'FREQ=MONTHLY;BYDAY=1MO;COUNT=12', }, { rrule: 'FREQ=YEARLY;COUNT=5', title: 'Event on the 8th of February for 5 years', start: Temporal.ZonedDateTime.from('2024-02-08T16:00:00+01:00[Europe/Berlin]'), end: Temporal.ZonedDateTime.from('2024-02-08T17:55:00+01:00[Europe/Berlin]'), id: 181920 } ] });

Supported rules

RuleSupported valuesRequired
FREQDAILY, WEEKLY, MONTHLY or YEARLYYes
COUNTNumberNo
INTERVALNumberNo
BYDAY - compatible with all frequenciesMO, TU, WE, TH, FR, SA, SU. Can optionally be prefixed with a position (e.g., 1MO for first Monday, -1FR for last Friday) but can’t be updated using drag & drop.No
BYMONTHDAY - compatible with MONTHLY(Single) Positive integer 1-31. Does not support list of values, since such lists cannot be updated in a predictable way using drag & drop.No
UNTILFloating date, for example 20240101 or date-time 20240101T120000No
WKSTMO, TU, WE, TH, FR, SA, SUNo

exdate

You can exclude certain dates or date-times from a recurrence set using the exdate rule. The expected format is RFC5455 floating date (e.g. 20240101) or datetime (e.g. 20240101T120000). For example:

const recurringEventWithExclusions = { id: 123, title: 'Weekly event', start: Temporal.ZonedDateTime.from('2024-02-05T14:00:00+01:00[Europe/Berlin]'), end: Temporal.ZonedDateTime.from('2024-02-05T15:00:00+01:00[Europe/Berlin]'), // will create a recurrence set of 3 events: 2024-02-05 14:00, 2024-02-26 14:00, 2024-03-04 14:00 rrule: 'FREQ=WEEKLY;COUNT=5', exdate: [ '20240212T140000', '20240219T140000' ] }

Events service

When using this plugin, you can no longer use the regular events service plugin. Instead, you now need to import the events service plugin from this package:

import { createEventRecurrencePlugin, createEventsServicePlugin } from "@schedule-x/event-recurrence"; const recurrencePlugin = createEventRecurrencePlugin(); const eventsServicePlugin = createEventsServicePlugin(); const calendar = createCalendar({ /* other config */ plugins: [ recurrencePlugin, eventsServicePlugin ] }); calendar.render(document.getElementById('calendar')); // Add an event eventsServicePlugin.add({ id: 1, title: 'New event', start: Temporal.ZonedDateTime.from('2024-02-05T14:00:00+01:00[Europe/Berlin]'), end: Temporal.ZonedDateTime.from('2024-02-05T15:00:00+01:00[Europe/Berlin]'), rrule: 'FREQ=WEEKLY;COUNT=3' }); // Update eventsServicePlugin.update({ id: 1, title: 'New event', start: Temporal.ZonedDateTime.from('2024-02-05T14:00:00+01:00[Europe/Berlin]'), end: Temporal.ZonedDateTime.from('2024-02-05T15:00:00+01:00[Europe/Berlin]'), rrule: 'FREQ=WEEKLY;COUNT=10' }) // Get one event with id 123 const event = eventsServicePlugin.get(123); // Get all const events = eventsServicePlugin.getAll(); // Remove an event with id 123 eventsServicePlugin.remove(123);
Last updated on