Recurring Events
Repeat an event daily, weekly, monthly or yearly with a practical subset of the iCalendar RRULE grammar — as a string or a typed object. The event’s start acts as DTSTART; occurrences inherit its time and duration.
// String form (RFC 5545 RRULE subset)…
recurrence: 'FREQ=WEEKLY;BYDAY=MO,WE,FR;COUNT=10'
// …or the equivalent object form
recurrence: {
freq: 'weekly', // 'daily' | 'weekly' | 'monthly' | 'yearly'
interval: 1, // every N periods
byDay: [1, 3, 5], // 0 = Sunday … 6 = Saturday
count: 10 // or: until: new Date(2027, 0, 1)
}
// Cancel individual occurrences by date:
exdates: [new Date(2026, 7, 19)]Five recurring patterns
Sun
Mon
Tue
Wed
Thu
Fri
Sat
30
31
Sep 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Oct 1
2
3
Supported rule parts
| RRULE | Object form | Meaning |
|---|---|---|
FREQ=DAILY|WEEKLY|MONTHLY|YEARLY | freq | Base frequency (required). |
INTERVAL=2 | interval | Every 2nd day/week/month/year. |
COUNT=10 | count | Stop after 10 occurrences, counted from the event start. |
UNTIL=20261231 | until | Last possible occurrence date (inclusive). |
BYDAY=MO,WE,FR | byDay: [1,3,5] | Weekly: which weekdays. |
BYDAY=2TU / -1FR | byNthDay | Monthly: the 2nd Tuesday / last Friday. |
BYMONTHDAY=1,15 | byMonthDay | Monthly: on these days of the month. |
| — | exdates: Date[] | Skip occurrences on these days (cancelled instances). |
Behavior details
- Occurrences keep the wall-clock time of the original event across DST changes.
- Monthly rules skip months where the day doesn’t exist (Jan 31 → no Feb 31), matching Google Calendar.
- Yearly rules starting Feb 29 only fire in leap years.
- Recurring instances show a ↻ mark. Dragging or resizing one opens a confirm popover with “This event” (detaches the occurrence) and “This and following” (splits the series at that point) — like Google Calendar.
- The details popover offers “Delete this occurrence” (adds an exdate) and “Delete series”.
- Expansion is windowed to the visible range and hard-capped at 1000 occurrences per event, so infinite rules are safe.
Editing a series —
both “this event” and “this and following” edits are built in: onSeriesDetach / onSeriesSplit report the results, COUNT and exdates are re-partitioned automatically, and weekly BYDAY lists re-anchor when the drag changes the weekday. The pure helpers detachOccurrence, excludeOccurrence and splitSeries are exported for data-layer use.