forceCalendar
Interface Package

Web Components

The forcecal-main custom element -- attributes, API, events, and lifecycle.

forcecal-main

The primary Web Component. Renders a full calendar with header navigation, view switching, and event display.

<forcecal-main
  view="month"
  date="2026-03-01"
  locale="en-US"
  timezone="America/New_York"
  week-starts-on="0"
  height="600px"
></forcecal-main>

Observed Attributes

These HTML attributes are reactive -- changes trigger re-renders.

AttributeTypeDefaultDescription
viewstring'month''month', 'week', 'day'
datestringTodayISO date string
localestring'en-US'BCP 47 locale
timezonestringSystemIANA timezone
week-starts-onstring'0'0=Sunday, 1=Monday
heightstring'auto'CSS height value
const el = document.querySelector('forcecal-main');
el.setAttribute('view', 'week');
el.setAttribute('timezone', 'Asia/Tokyo');

JavaScript API

addEvent(eventData)

el.addEvent({
  title: 'Meeting',
  start: new Date('2026-03-01T10:00:00'),
  end: new Date('2026-03-01T11:00:00'),
});

updateEvent(eventId, updates)

el.updateEvent('evt_123', { title: 'Updated Meeting' });

deleteEvent(eventId)

el.deleteEvent('evt_123');

getEvents()

Returns all events from the internal calendar instance.

setView(viewType)

el.setView('week');

setDate(date)

el.setDate(new Date('2026-06-15'));

next()

Navigate to the next period.

previous()

Navigate to the previous period.

today()

Navigate to today.

Custom Events

The component dispatches these CustomEvents with bubbles: true and composed: true (crosses Shadow DOM boundaries).

EventdetailWhen
calendar-navigate{ date, view, direction }Navigation occurs
calendar-view-change{ view }View type changes
calendar-event-add{ event }Event creation requested
calendar-event-update{ eventId, updates }Event update requested
calendar-event-remove{ eventId }Event deletion requested
calendar-event-added{ event }Event was added
calendar-event-updated{ event }Event was updated
calendar-event-deleted{ eventId }Event was deleted
calendar-date-select{ date }Date cell clicked
el.addEventListener('calendar-event-added', (e) => {
  console.log('Event created:', e.detail.event);
});

el.addEventListener('calendar-date-select', (e) => {
  console.log('Date selected:', e.detail.date);
});

Template Structure

The component renders this internal structure inside its Shadow DOM:

<div class="fc-calendar">
  <div class="fc-header">
    <button class="fc-today-btn">Today</button>
    <button class="fc-prev-btn">&lt;</button>
    <button class="fc-next-btn">&gt;</button>
    <h2 class="fc-title">March 2026</h2>
    <button class="fc-new-event-btn">+ New Event</button>
    <div class="fc-view-switcher">
      <button>Month</button>
      <button>Week</button>
      <button>Day</button>
    </div>
  </div>
  <div class="fc-body">
    <!-- View renderer output -->
  </div>
</div>

BaseComponent

All Web Components extend BaseComponent, which provides:

Lifecycle

MethodCalled When
initialize()Component first connected to DOM
mount()After initialization
render()When state changes require a re-render
afterRender()After render completes
unmount()Component disconnected from DOM
cleanup()Final cleanup (remove listeners)

State Management

// Inside a component
this.setState({ loading: true });
const state = this.getState();

Properties

this.setProp('locale', 'en-US');
const locale = this.getProp('locale');

DOM Helpers

// Query within shadow root
const btn = this.$('.fc-today-btn');
const allBtns = this.$$('.fc-btn');

Event Emission

// Emit a custom event that crosses shadow DOM boundaries
this.emit('calendar-navigate', { date: new Date(), view: 'month' });

Listener Management

Listeners registered via addListener() are automatically cleaned up on disconnect:

this.addListener(this.$('.fc-prev-btn'), 'click', () => this.previous());

Re-render Preservation

BaseComponent preserves scroll positions and focus across re-renders. Before rendering, it saves the current scroll position and active element reference. After rendering, it restores both.

View Renderers

Each view has a dedicated renderer that produces DOM content:

MonthViewRenderer

Renders a grid of weeks. Each day cell shows up to 3 events with a "+N more" overflow indicator.

  • Pure JS rendering (no innerHTML) for Locker Service compatibility
  • Respects weekStartsOn configuration
  • Highlights today and selected date
  • Shows week numbers when enabled

WeekViewRenderer

Renders a 7-day timeline with hourly slots.

  • All-day events displayed in a header row
  • Timed events positioned based on start/end times
  • Business hours highlighted
  • Overlap groups handled via calculateEventPositions()

DayViewRenderer

Renders a single-day timeline with hourly slots.

  • Same layout principles as WeekViewRenderer
  • More detail per event (full title, time, location)
  • All-day events in header