Search

Custom Calendar Using LWC

Updated: Jun 23

You can now create custom calendar swiftly using LWC. This custom calendar gives you ease to set reminders, save special dates and a lot more to make your business application on the move.


sampleCustomCalendar.html

<template>

<div class="container">

<section role="dialog" tabindex="-1" aria-label="Meaningful description" aria-modal="true" aria-describedby="modal-content-id1" class="slds-modal slds-modal_large slds-fade-in-open">

<div class="slds-modal__container modal-container">

<header class="slds-modal__header slds-modal__header_empty">/header>

<div class="slds-modal__content slds-p-around_medium" id="modal-content-id2">

<div class="slds-grid slds-wrap">

<div class="slds-col slds-large-size_6-of-12 slds-medium-size_6-of-12 slds-small-size_6-of-12 slds-p-left_large calendar-content">

<h1 class="cal-h1">Select a date</h1>

<p class="cal-para">Select a date

</p>

</div>

</div>

<div class="slds-media__body slds-modal__content">

<div class="slds-m-around_medium slds-theme_default">

<div class="calendar">

<div class="slds-grid slds-wrap">

<div class="slds-col slds-large-size_3-of-12 slds-medium-size_3-of-12 slds-small-size_3-of-12 calender-previous-btn">

<button class="slds-button slds-button_stretch previous-btn" onclick={shiftLeft} disabled={isPreviousDisabled} name="Previous">

Previous

</button>

</div>

<div class="slds-col slds-large-size_6-of-12 slds-medium-size_6-of-12 slds-small-size_6-of-12 calender-month-btn">

<button class="slds-button slds-button_stretch month-btn">

<span class="calender-header-text-month calendar-month">{month}</span>&nbsp; &nbsp;

<span class="calender-header-text-year calendar-year">{year}</span>

</button>

</div>

<div class="slds-col slds-large-size_3-of-12 slds-medium-size_3-of-12 slds-small-size_3-of-12 calender-next-btn">

<button class="slds-button slds-button_stretch next-btn" onclick={shiftRight} name="Next">

Next

</button>

</div>

</div>

<lightning-layout class="calendar__nav slds-p-left_large">

<lightning-layout-item flexibility="auto" class="slds-p-left_medium">

<div class="cal-monday">MONDAY</div>

</lightning-layout-item>

<lightning-layout-item flexibility="auto" class="slds-p-left_small">

<div class="cal-tuesday">TUESDAY</div>

</lightning-layout-item>

<lightning-layout-item flexibility="auto">

<div class="cal-wednesday">WEDNESDAY</div>

</lightning-layout-item>

<lightning-layout-item flexibility="auto">

<div class="cal-thursday">THURSDAY</div>

</lightning-layout-item>

<lightning-layout-item flexibility="auto" class="slds-p-left_medium">

<div class="cal-friday">FRIDAY</div>

</lightning-layout-item>

<lightning-layout-item flexibility="auto" class="slds-p-left_xx_large">

<div class="cal-saturday">SATURDAY</div>

</lightning-layout-item>

&nbsp;

<lightning-layout-item flexibility="auto" class="slds-p-left_xx_large">

<div class="cal-sunday">SUNDAY</div>

</lightning-layout-item>

</lightning-layout>

<div class="main-cal">

<table class="calendar__body" onclick={selectHandler} lwc:dom="manual"></table>

</div>

</div>

</div>

</div>

</div>

</div>

</section>

<div class="slds-backdrop slds-backdrop_open"></div>

</div>

</template>


sampleCustomCalendar.js

import { LightningElement, track, api } from "lwc";

export default class Calender extends LightningElement {

@track calenderModal = true;

@track isPreviousDisabled = false;

@track month;

@track year;

@track date;

@track selectedDate;

@api inputLabel = "Select Date";

jsCalInit = false;

@track calenderModalCloseButton = false;


renderedCallback() {

if (this.jsCalInit) {

return;

}

this.jsCalInit = true;

this.initializeJsCalendar();

}


handleCalenderInfo(e) {

var cal = { date: this.selectedDate, calenderModal: this.calenderModal, calenderModalCloseButton: this.calenderModalCloseButton};

const custEvent = new CustomEvent("calenderinfo", {

detail: cal

});

this.dispatchEvent(custEvent);

}

}


initializeJsCalendar() {

this.displayed_date = new Date(); //date wich calendar displays now

this.current_day = this.displayed_date.getDate(); //current world time

this.selected_date = this.displayed_date; //date that user's selected

this.body_node = this.template.querySelector(".calendar__body");

this.year_node = this.template.querySelector(".calendar-year");

this.month_node = this.template.querySelector(".calendar-month");

this.setDateTo(this.displayed_date);

this.date = this.selected_date.toLocaleDateString("en-US");

this.selectedDate = this.selected_date.toLocaleDateString("en-US");

}


closeCalenderPopup(e) {

this.calenderModalCloseButton = true;

this.calenderModal = false;

this.handleCalenderInfo(e);

}


createDaysArray(date) {

let prev_month_last_day = new Date( //number of the last day of the previous month

date.getFullYear(),

date.getMonth(),

0

).getDate(),

first_week_day = new Date( //number of the first day of the current month f.e. monday->1, wednesday->3

date.getFullYear(),

date.getMonth(),

1

).getDay(),

current_month_last_day = new Date(

date.getFullYear(),

date.getMonth() + 1,

0

).getDate(),

days_array = new Array(42),

i = 0; // iterator for all three parts of array


if (first_week_day == 0) first_week_day = 7; //if it was sunday


let first_array_element = prev_month_last_day - first_week_day + 2;

//adds last days of previous month

for (i = 0; i < first_week_day - 1; ++i) {

days_array[i] = {

number: first_array_element + i,

from: "prev month"

};

}

//adds days of current month

for (let k = 1; k <= current_month_last_day; ++k) {

days_array[i] = {

number: k,

from: "currnet month",

weekend: i % 7 > 4

};

i++;

}

//adds days of next month

for (let k = 0; i < days_array.length; ++k) {

days_array[i] = {

number: k + 1,

from: "next month"

};

i++;

}

return days_array;

}


//returns a fulfilled and styled table DOM element

createCalendarBody(date, current_month = false) {

let days_array = this.createDaysArray(date),

table = document.createDocumentFragment(),

i = 0;


for (let j = 0; j < 6; ++j) {

let tr = document.createElement("tr");


for (let k = 0; k < 7; ++k) {

let td = document.createElement("td");

td.innerHTML = days_array[i].number;

tr.appendChild(td);


//add the styles that depend on what month the day belongs to

td.classList.add("calendar-cell");

td.classList.add("slds-text-align_center");

let day = new Date();


if (days_array[i].from !== "currnet month") {

if(days_array[i].from === "prev month"){

td.classList.add("prev-last-dates");

}

else if(days_array[i].from === "next month"){

td.classList.add("next-last-dates");

}

}

else {

if (current_month && days_array[i].number < day.getDate()) {

td.classList.add("slds-text-color_inverse-weak");

td.classList.add("prev-last-dates");

}

if (current_month) {

this.isPreviousDisabled = true;

} else {

this.isPreviousDisabled = false;

}

if (current_month && this.selected_date.getDate() == days_array[i].number) {

td.classList.add("selected_date");

td.classList.add("slds-theme_shade");

}

}

++i;

}

table.appendChild(tr);

}

return table;

}


//returns month name from date

getMonthName(date) {

const month_names = [

"January",

"February",

"March",

"April",

"May",

"June",

"July",

"August",

"September",

"October",

"November",

"December"

];

return month_names[date.getMonth()];

}


//if the received date corresponds to the current month and year returns true

isThisMonthCurrent(date) {

let current = new Date();

if (

current.getFullYear() == date.getFullYear() &&

current.getMonth() == date.getMonth()

)

return true;

else return false;

}


//redraws the body according to the received date

setDateTo(date) {

let current_month = this.isThisMonthCurrent(date), //if it is current month, current day will be highlighted

new_body = this.createCalendarBody(date, current_month);

this.year_node.innerHTML = date.getFullYear();

this.month_node.innerHTML = this.getMonthName(date);

this.body_node.innerHTML = "";

this.body_node.appendChild(new_body);

}


//redraws the calendar a month in backward

shiftLeft() {

this.displayed_date = new Date( //set the day to prev month

this.displayed_date.getFullYear(),

this.displayed_date.getMonth() - 1,

1

);

this.setDateTo(this.displayed_date);

}


//redraws the calendar a month in forward

shiftRight() {

this.displayed_date = new Date( //set the day to next month

this.displayed_date.getFullYear(),

this.displayed_date.getMonth() + 1,

1

);

this.setDateTo(this.displayed_date);

}


//handles user clicks on cells

selectHandler(e) {

var futureDate = false;

if (e.target.classList.contains("prev-last-dates")){

let today = new Date();

if(this.displayed_date.getMonth() === today.getMonth() && this.displayed_date.getFullYear() === today.getFullYear()) return;

futureDate = true;

}


if (e.target.classList.contains("calendar-cell") && !e.target.classList.contains("next-last-dates") && !e.target.classList.contains("prev-last-dates")) {

this.selected_date = new Date(

this.displayed_date.getFullYear(),

this.displayed_date.getMonth(),

e.target.innerHTML

);

}

else if (e.target.classList.contains("next-last-dates") && e.target.classList.contains("calendar-cell")){

this.selected_date = new Date(

this.displayed_date.getFullYear(),

this.displayed_date.getMonth()+1,

e.target.innerHTML

);

}

else if (e.target.classList.contains("prev-last-dates") && e.target.classList.contains("calendar-cell")){

this.selected_date = new Date(

this.displayed_date.getFullYear(),

this.displayed_date.getMonth()-1,

e.target.innerHTML

);

}


this.selectedDate = this.selected_date.toLocaleDateString("en-US");

if (!e.target.classList.contains("prev-last-dates") || (e.target.classList.contains("prev-last-dates") && futureDate)) {

this.calenderModal = false;

this.calenderModalCloseButton = false;

this.handleCalenderInfo(e);

}

}

}


sampleCustomCalendar.css

.container { font-family: "Arial", "Arial", Arial, "Arial", Arial; }



51 views0 comments

Recent Posts

See All