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:
- Some rules just haven’t been implemented yet. If there is a rule that you would like to see implemented, and you think this rule could be updated in a predictable way using drag & drop or resize, please open an issue on GitHub.
- Some iCalendar rules don’t make sense in an interactive calendar. Consider for example
FREQ=MONTHLY;BYDAY=1SU,4TH; COUNT=20
where dragging one occurrence might offset the other occurrences in a non-symmetrical way, which might not have been intended when creating the rule.
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',
},
{
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
Rule | Supported values | Required |
---|---|---|
FREQ | DAILY , WEEKLY , MONTHLY or YEARLY | Yes |
COUNT | Number | No |
INTERVAL | Number | No |
BYDAY - compatible with DAILY and WEEKLY | MO , TU , WE , TH , FR , SA , SU | 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 |
UNTIL | Floating date , for example 20240101 or date-time 20240101T120000 | No |
WKST | MO , TU , WE , TH , FR , SA , SU | No |
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);