Skip to content

calendaryjs-plugin-icsv0.1.5

Turn the events calendaryjs generates into a standard .ics VCALENDAR that Apple Calendar, Google Calendar, Outlook and anything else can subscribe to.

Terminal window
npm i calendaryjs calendaryjs-plugin-ics
import { calendary } from "calendaryjs";
import { every, date } from "calendaryjs/builder";
import { toICS } from "calendaryjs-plugin-ics";
const cal = calendary();
cal.addGroup({
id: "holidays",
events: [
every("year").on(date(1, 1)).title("New Year"),
every("year").on(date(12, 25)).title("Christmas"),
],
});
const events = cal.getEventsInRange("2025-01-01", "2025-12-31");
const ics = toICS(events, { calendarName: "Holidays" });
// → write `ics` to a .ics file, or serve it from an endpoint

Events arrive already expanded — the core has applied recurrence, the startDate / endDate validity window, exceptions and overrideDates before you call toICS(). So the exporter emits one VEVENT per occurrence and never needs an RRULE. Non-Gregorian recurrences (lunar, hijri, formula) therefore export correctly, because every occurrence is just a concrete date by the time it reaches ICS.

calendaryjs ICS
date + startTime / endTime DTSTART / DTEND (floating local time)
date (all-day / no time) DTSTART;VALUE=DATE + exclusive DTEND
duration (minutes) DURATION (when endTime is absent)
title SUMMARY
description / location / url DESCRIPTION / LOCATION / URL
categories / status CATEGORIES / STATUS
priority (z-index) PRIORITY (inverted, 1 = highest)
color / icon COLOR / IMAGE (RFC 7986)
reminders[] (minutes before) VALARM with TRIGGER:-PTnM
source / groupId / id + date a stable, unique UID

Timed events export as floating local time (no Z, no TZID) — the core stays timezone-neutral, so occurrences render in the viewer’s local zone. Reminder and duration units are minutes.

toICS(events, {
prodId, // PRODID. Default "-//calendaryjs//calendaryjs-plugin-ics//EN"
calendarName, // X-WR-CALNAME — the calendar's display name
method, // METHOD, e.g. "PUBLISH"
dtstamp, // DTSTAMP for every event (pass a fixed Date for stable output)
priorityMap, // override priority → ICS PRIORITY (return 0 to omit)
});

eventToVEvent(event, options?) serializes a single occurrence to one VEVENT block (no VCALENDAR wrapper).

ExportstoICS(events, options?) · eventToVEvent(event, options?) · defaultPriorityMap · low-level helpers (veventLines, escapeText, foldLine) · types (ICSEvent, ICSReminder, ICSOptions). Not a .use() plugin — there is nothing to register.

Feed it any expanded occurrences: cal.getEventsInRange(...), cal.search()...getEvents(), or a filtered subset (e.g. one group / one source) — whatever you pass is exactly what the .ics contains.

  • RRULE compaction for Gregorian-expressible recurrences (with EXDATE / RECURRENCE-ID for exceptions).
  • ICS import (.ics → event configs).