Create Custom Calendar Using Lightning Web Components in Salesforce

In Salesforce, we need a calendar to manage events, meetings, deadlines, and tasks directly within the platform. Instead of switching between external tools like Google Calendar or Outlook, users can track everything in one place using a custom reusable LWC calender, where it can be deployed on any lightning page.

The most efficient way to create an LWC calendar is by using the FullCalendar Js library. Let’s see how to create a custom calendar using the Lightning web component in Salesforce.

Create a Custom Calendar Using Lightning Web Components

We will create a custom reusable calendar using the FullCalendar Js library. For that, we will first download the FullCalndar library as a static resource.

Download the zip file from the FullCalendar JS library from the link https://fullcalendar.io/docs/v5/initialize-globals.

In this, I have downloaded version 5 of the JS library, and it was throwing an error while rendering the component. Even though by defining the right path, FullCalender zipped > library files, I was getting the below error:

How to add Js calendar in Salesforce LWC

To avoid this error after implementation, extract the zipped folder and open the lib file.

Create Custom calendar using JS library

In the main.js file, you see the code:

var FullCalendar = (function (exports) {

Replace this code with the code block below:

function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ?
factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = global || self, factory(global.FullCalendar = {}));
}(this, function (exports) {

Now, save the changes in the main.js file. After this, compress the lib file as separate zipped folder as name it as FullCalendar.

To use this library in the LWC, create a static resource in Salesforce following the steps below.

  1. Navigate to the setup page and search, then select Static Resource from the quick find.
JS Calendar in Lightning web components
  1. In the Static resource setup, create a new static resource and name it as FullCalendar, then upload the zipped folder FullCalendarJs.

Ensure to set the Cache Control to Public, then click on the Save button.

How create an LWC calendar using JS library

With the static resource uploaded, we will now refer to this JS library in the Lightning Web Component to add the calendar.

  1. Create the LWC component customCalendar and enter the code below in the HTML file.

We have used the <div> tag because we will render the calendar component under this div.

<template>
    <lightning-card>
        <div class="fullcalendar"></div>
    </lightning-card>
</template>
  1. To import the JS calendar library and define the logic of displaying the calendar, enter the code below in the customCalendar.js file.

In this, we have imported the JS library FullCalendarJS from the static resource resourceUrl/FullCalendar.

The import { loadStyle, loadScript } from ‘lightning/platformResourceLoader is used to import any external CSS or JS files.

import { LightningElement } from 'lwc';
import FullCalendarJS from '@salesforce/resourceUrl/FullCalendar';
import { loadStyle, loadScript } from 'lightning/platformResourceLoader';

export default class CustomCalendar extends LightningElement {

    connectedCallback() {
        Promise.all([
            loadStyle(this, FullCalendarJS + '/lib/main.css'),
            loadScript(this, FullCalendarJS + '/lib/main.js')
        ])
        .then(() => {
            this.initializeCalendar();
        })
        .catch(error => console.log(error))
    }
    initializeCalendar() { 
        const calendarEl = this.template.querySelector('div.fullcalendar');
        const calendar = new FullCalendar.Calendar(calendarEl, {});
        calendar.render();
    }
}

In the above code, we have used connectedCallback to load the main style sheet and main JS file and provide a Fullcalendar instance to the component, which we have used in the initializeCalendar method.

In the method initializeCalender, we have the following syntax to create a calendar instance in LWC:

const calendar = new FullCalendar.Calendar(calendarElement, optionsObject);
  1. After this, enter the code below in the meta.xml file to make the component accessible on the Lightning pages.
<isExposed>true</isExposed>
    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>
    </targets>

Deploy the Lightning Web Component to the Lightning page, and the calendar will display the current month.

Lightning Web component Cusotm Calenadar

This way, we can create a reusable custom calendar in Salesforce with Lightning web components.

Now, this was a LWC calendar with header action through which we can navigate to months using next and previous arrow. But the UI of this calendar is very basic with header where we can see only monthly view.

In the later steps, we will make this calendar more dynamic by modifying the header, where we will add calendar icons. The user can change the calendar view to monthly, weekly, or current day.

Display Custom Calendar View in Month, Week, and Day

In the custom calendar, we have used the header from the JS library, so we cannot modify the header to add buttons and functionality to change the calendar view to week, month, and day.

The first thing that we will do here is remove the header by setting the header toolbar to false.

In the JS file, enter the code below inside the initializeCalendar method to remove the header.

const calendarEl = this.template.querySelector('div.fullcalendar');
const calendar = new FullCalendar.Calendar(calendarEl, {
  headerToolbar: false
}
calendar.render();

With this code, the header will be removed from the custom calendar.

After this, go to the HTML file and enter the code below to add a header with a calendar icon.

<template>
    <lightning-card>
        <div class="calendar-card">
            <div class="slds-theme_shade slds-box">
                <div class="slds-grid slds-gutters">
                    <div class="slds-col slds-size_1-of-3">
                        <div class="slds-media slds-no-space slds-grow">
                            <div class="slds-media__figure">
                            </div>
                            <div class="slds-media__body">
                                <p class="slds-line-height_reset" data-aura-rendered-by="168:1393;a">Calendar</p>
                                <h1 class="slds-page-header__title slds-m-right_small slds-align-middle slds-truncate" data-aura-rendered-by="170:1393;a">{calendarTitle}</h1>
                            </div>
                        </div>
                    </div>

                    <div class="slds-col slds-size_2-of-3 slds-clearfix">
                        <div class="slds-float_right slds-p-top_xx-small">
                            <lightning-button-icon 
                                variant="border-filled" 
                                icon-name="utility:chevronleft" 
                                value="previous"
                                onclick={calendarActionsHandler}>
                            </lightning-button-icon>

                            <lightning-button-icon 
                                variant="border-filled" 
                                icon-name="utility:chevronright" 
                                value="next" 
                                onclick={calendarActionsHandler}>
                            </lightning-button-icon>

                            <lightning-button-icon 
                                variant="border-filled" 
                                icon-name="utility:refresh" 
                                class="slds-m-left_medium" 
                                value="refresh" 
                                onclick={calendarActionsHandler}>
                            </lightning-button-icon>
                            <lightning-button-menu alternative-text="Show menu" variant="border-filled" 
                                icon-name="utility:event" class="slds-m-horizontal_small" 
                                menu-alignment="auto" onselect={changeViewHandler}>
                                <template for:each={viewOptions} for:item="menuItem">
                                    <lightning-menu-item
                                    key={menuItem.viewName}
                                    value={menuItem.viewName}
                                    label={menuItem.label}
                                    checked={menuItem.checked}>
                                </lightning-menu-item>
                                </template>
                            </lightning-button-menu>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <div class="fullcalendar"></div>
    </lightning-card>
</template>

In this HTML code, we have defined the buttons to move to the previous and next months, and a dropdown from which we can change the calendar view as monthly, weekly, and daily.

Each action is assigned a value attribute to help identify which specific action was triggered in the JavaScript method. In the JS method, implement the calendarActionsHandler function. Then it will retrieve the action value by accessing event.target.value and assign this value to a constant variable, actionName.

Now, we will define the events in the JS file to handle the buttons.

 calendarActionsHandler(event) {
    const actionName = event.target.value;
    if(actionName === 'previous') {
        this.calendar.prev();
    } else if(actionName === 'next') {
        this.calendar.next();
    } else if(actionName === 'today') {
        this.calendar.today();
    } else if(actionName === 'new') {
        
    } else if(actionName === 'refresh') {

    }
    this.calendarTitle = this.calendar.view.title;
}

For changing the view to month, week, and day, create one more class-level variable in the JS file as viewOptions, which is an array-type variable that will have the following elements.

viewOptions = [
    {
        label: 'Day',
        viewName: 'timeGridDay',
        checked: false
    },
    {
        label: 'Week',
        viewName: 'timeGridWeek',
        checked: false
    },
    {
        label: 'Month',
        viewName: 'dayGridMonth',
        checked: true
    }
];

Open the HTML file and set variant=”border-filled”, icon-name=”utility:event”, menu-alignment=”auto”, and add a small horizontal margin for spacing.

Also, specify the onselect handler as changeViewHandler. Within this, use a  for-each directive to loop through the viewOptions array from the JS file and dynamically generate a for-each option.

<lightning-button-menu alternative-text="Show menu" variant="border-filled" 
    icon-name="utility:event" class="slds-m-horizontal_small" 
    menu-alignment="auto" onselect={changeViewHandler}>
    <template for:each={viewOptions} for:item="menuItem">
        <lightning-menu-item
        key={menuItem.viewName}
        value={menuItem.viewName}
        label={menuItem.label}
        checked={menuItem.checked}>
    </lightning-menu-item>
    </template>
</lightning-button-menu>

Now, when we need to handle changing views in the calendar, from month to week or day, we have defined an event in the JS file as changeViewHandler.

The changeViewHandler method manages the logic for switching between calendar views or navigating to a standard Salesforce list view.

When a user selects an option, it captures the view name from event.detail.value. If the selected view is not ‘listView‘, the method updates the calendar to display the chosen view using this.calendar.changeView(viewName).

First, import the NavigationMixin library.

import { NavigationMixin } from "lightning/navigation";

Now, define the method below.

changeViewHandler(event) {
    const viewName = event.detail.value;
    if(viewName != 'listView') {
        this.calendar.changeView(viewName);
        const viewOptions = [...this.viewOptions];
        for(let viewOption of viewOptions) {
            viewOption.checked = false;
            if(viewOption.viewName === viewName) {
                viewOption.checked = true;
            }
        }
        this.viewOptions = viewOptions;
        this.calendarTitle = this.calendar.view.title;
    } else {
        this.handleListViewNavigation(this.objectApiName);
    }
}

At last, deploy all the changes to the source org, and navigate to the Lightning page where you have deployed the Calendar LWC.

If the changes are not visible, then open the page in Lightning App Builder from settings> Edit page.

Week view:

Custom LWC calendar in Salesforce

Day view:

Create Weekly Calendar in Salesforce using LWC

Navigation for previous and next month:

Change months in Salesforce LWC calendar

This is how the final output of the Custom LWC calendar will look. We can navigate through months and change the view to monthly, weekly, or daily.

By following the above steps, you can create a dynamic calendar using Lightning Web Components and deploy it in your Salesforce org. Just make sure to upload the library correctly and update the lib code as explained.

You may also like to read:

Agentforce in Salesforce

DOWNLOAD FREE AGENTFORCE EBOOK

Start with AgentForce in Salesforce. Create your first agent and deploy to your Salesforce Org.

Salesforce flows complete guide

FREE SALESFORCE FLOW EBOOK

Learn how to work with flows in Salesforce with 5 different real time examples.