Quick Start
Render a calendar, apply a snapshot, and listen without duplicating persistence.
Render a browser calendar
Install Core 2.5.7 and Interface 1.9.0, then include the element:
<forcecal-main id="calendar" view="month" date="2026-10-05" height="600px"></forcecal-main>In your browser entry module:
import '@forcecalendar/interface';
const calendar = document.querySelector('#calendar');
calendar.events = [
{
id: 'planning',
title: 'Planning',
start: new Date(2026, 9, 5, 9),
end: new Date(2026, 9, 5, 10),
location: 'Room A',
},
{
id: 'offsite',
title: 'Team offsite',
allDay: true,
start: new Date(2026, 9, 6),
end: new Date(2026, 9, 7, 23, 59, 59, 999),
},
];
calendar.addEventListener('calendar-events-set', ({ detail }) => {
console.log('Snapshot applied:', detail.added.length, 'new events');
});
calendar.addEventListener('calendar-event-updated', ({ detail }) => {
console.log('Local change to persist:', detail.event.id);
});These examples deliberately construct local civil dates: JavaScript's month index is zero-based. The offsite covers October 6–7 inclusive. For API data, agree on the source timezone and all-day boundary before converting it.
Click an event to view its details, edit it, or confirm deletion. Those actions change local calendar state. Connect your own backend, handle rejected writes and refresh authoritative state; the npm Interface does not save to a server for you.
Snapshots and range loading
events/setEvents() reconcile a complete snapshot. A snapshot emits one calendar-events-set, not per-event mutation events, so loading server data does not trigger duplicate saves.
Use calendar-range-change to request the visible window. It fires initially and after navigation/view changes; { start, end } has an inclusive end and uses the browser's local timezone. Protect asynchronous requests from out-of-order responses:
let request = 0;
async function loadRange(start, end) {
const current = ++request;
// Implement fetchEvents in your application with authorization and error handling.
const rows = await fetchEvents(start, end);
if (current === request && calendar.isConnected) calendar.events = rows;
}
calendar.addEventListener('calendar-range-change', ({ detail }) => {
loadRange(detail.start, detail.end).catch(console.error);
});
const initialRange = calendar.getVisibleRange();
if (initialRange) loadRange(initialRange.start, initialRange.end).catch(console.error);For a single-event mutation use addEvent, updateEvent or deleteEvent. Listen to one spelling of each event: the legacy -add and current -added forms are aliases for the same mutation, not separate request/success stages.
Headless Core
import { Calendar } from '@forcecalendar/core';
const calendar = new Calendar({ view: 'month', date: new Date(2026, 9, 5) });
try {
calendar.addEvent({
id: 'planning', title: 'Planning',
start: new Date(2026, 9, 5, 9), end: new Date(2026, 9, 5, 10),
});
console.log(calendar.getEventsForDate(new Date(2026, 9, 5)));
} finally {
calendar.destroy();
}Core returns data and does not render a UI. Use the React, Vue, or Salesforce guide for those hosts. Continue with Web Component methods and migration.