Calendar (FullCalendar)
The Most Popular JavaScript Calendar.
FullCalendar documentationHow to use
Import the files you need for your calendar from FullCalendar. The core JavaScript file is required and one of the grid plugins, e.g. daygrid
. We also recommend you import moment.js
and helpers
file too.
(async () => {
const {Calendar} = await import(/* webpackChunkName: 'fullcalendar.core' */ '@fullcalendar/core');
const [{default: dayGridPlugin}, {default: timeGridPlugin}, {default: listPlugin}, {default: interactionPlugin, Draggable}, {default: bootstrap5Plugin}, {default: moment}, helper] =
await Promise.all([
import(/* webpackChunkName: 'fullcalendar.daygrid' */ '@fullcalendar/daygrid'),
import(/* webpackChunkName: 'fullcalendar.timegrid' */ '@fullcalendar/timegrid'),
import(/* webpackChunkName: 'fullcalendar.list' */ '@fullcalendar/list'),
import(/* webpackChunkName: 'fullcalendar.interaction' */ '@fullcalendar/interaction'),
import(/* webpackChunkName: 'fullcalendar.bootstrap5' */ '@fullcalendar/bootstrap5'),
import(/* webpackChunkName: 'moment' */ 'moment'),
import(/* webpackChunkName: 'helpers' */ '../helpers')
]);
})();
By using code splitting and dynamic import techniques you don't need to worry about the size of the JavaScript file. Dashly will only import the necessary files when they are needed.
Basic usage
<div id="fullcalendarSimple" class="h-1000px"></div>
const calendarSimpleEl = document.getElementById('fullcalendarSimple');
if(calendarSimpleEl) {
(async () => {
const {Calendar} = await import(/* webpackChunkName: 'fullcalendar.core' */ '@fullcalendar/core');
const [{default: dayGridPlugin}, {default: timeGridPlugin}, {default: listPlugin}, {default: interactionPlugin, Draggable}, {default: bootstrap5Plugin}, {default: moment}, helper] =
await Promise.all([
import(/* webpackChunkName: 'fullcalendar.daygrid' */ '@fullcalendar/daygrid'),
import(/* webpackChunkName: 'fullcalendar.timegrid' */ '@fullcalendar/timegrid'),
import(/* webpackChunkName: 'fullcalendar.list' */ '@fullcalendar/list'),
import(/* webpackChunkName: 'fullcalendar.interaction' */ '@fullcalendar/interaction'),
import(/* webpackChunkName: 'fullcalendar.bootstrap5' */ '@fullcalendar/bootstrap5'),
import(/* webpackChunkName: 'moment' */ 'moment'),
import(/* webpackChunkName: 'helpers' */ '../helpers')
]);
let todayDate = moment().startOf('day'),
thisMonth = todayDate.format('YYYY-MM');
let calendarSimple = new Calendar(calendarSimpleEl, {
themeSystem: 'bootstrap5',
plugins: [dayGridPlugin, bootstrap5Plugin],
initialView: 'dayGridMonth',
headerToolbar: {
left: null,
center: 'title',
right: 'prev,next customToday'
},
buttonText: {
today: 'Today',
prev: 'Prev',
next: 'Next'
},
customButtons: {
customToday: {
text: 'Today',
click: () => {
calendarSimple.today();
}
}
},
events: [
{
title: 'Interview',
start: thisMonth + '05T10:30:00',
end: thisMonth + '05T13:30:00',
className: 'bg-primary'
}
]
});
calendarSimple.render();
})();
}
Drag & Drop events
<div id="fullcalendarDraggable" class="h-1000px"></div>
const calendarDraggableEl = document.getElementById('fullcalendarDraggable');
if(calendarDraggableEl) {
(async () => {
const {Calendar} = await import(/* webpackChunkName: 'fullcalendar.core' */ '@fullcalendar/core');
const [{default: dayGridPlugin}, {default: timeGridPlugin}, {default: listPlugin}, {default: interactionPlugin, Draggable}, {default: bootstrap5Plugin}, {default: moment}, helper] =
await Promise.all([
import(/* webpackChunkName: 'fullcalendar.daygrid' */ '@fullcalendar/daygrid'),
import(/* webpackChunkName: 'fullcalendar.timegrid' */ '@fullcalendar/timegrid'),
import(/* webpackChunkName: 'fullcalendar.list' */ '@fullcalendar/list'),
import(/* webpackChunkName: 'fullcalendar.interaction' */ '@fullcalendar/interaction'),
import(/* webpackChunkName: 'fullcalendar.bootstrap5' */ '@fullcalendar/bootstrap5'),
import(/* webpackChunkName: 'moment' */ 'moment'),
import(/* webpackChunkName: 'helpers' */ '../helpers')
]);
let todayDate = moment().startOf('day'),
yesterday = todayDate.clone().subtract(1, 'day').format('YYYY-MM-DD'),
today = todayDate.format('YYYY-MM-DD'),
tomorrow = todayDate.clone().add(1, 'day').format('YYYY-MM-DD'),
thisMonth = todayDate.format('YYYY-MM');
let calendarDraggable = new Calendar(calendarDraggableEl, {
themeSystem: 'bootstrap5',
plugins: [dayGridPlugin, interactionPlugin, bootstrap5Plugin],
initialView: 'dayGridMonth',
headerToolbar: {
left: null,
center: 'title',
right: 'prev,next customToday'
},
buttonText: {
today: 'Today',
prev: 'Prev',
next: 'Next'
},
customButtons: {
customToday: {
text: 'Today',
click: () => {
calendarDraggable.today();
}
}
},
editable: true,
droppable: true,
events: [
{
id: helper.setID(),
title: 'Interview',
start: thisMonth + '05T10:30:00',
end: thisMonth + '05T13:30:00',
className: 'bg-info',
location: 'Room 127',
description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit'
},
{
id: helper.setID(),
title: 'Team building trip',
start: thisMonth + '15',
end: thisMonth + '18',
className: 'bg-success',
location: 'Florida',
description: 'Integer ullamcorper metus sed urna laoreet, sed convallis leo pretium'
},
{
id: helper.setID(),
title: 'Team meeting',
start: thisMonth + '25T13:15:00',
end: thisMonth + '25T15:00:00',
classNames: 'bg-warning',
location: 'Conference room',
description: 'Maecenas aliquam lectus ut nibh gravida egestas'
},
{
id: helper.setID(),
title: 'Seminarium',
start: today,
allDay: true,
className: 'bg-success',
location: 'Hall',
description: 'Mauris eu massa ac mauris dapibus consequat a at quam'
},
{
id: helper.setID(),
title: 'Front-End Interview',
start: yesterday + 'T09:00:00',
end: yesterday + 'T10:15:00',
location: 'Room 201',
description: 'Ut facilisis odio at lectus ultricies mattis. Morbi a arcu rhoncus ligula lobortis aliquet a in est'
},
{
id: helper.setID(),
title: 'Meeting',
start: yesterday + 'T10:30:00',
end: yesterday + 'T11:30:00',
className: 'bg-success',
location: 'Office',
description: 'Nunc quis augue non odio porttitor mattis'
},
{
id: helper.setID(),
title: 'Lunch',
start: yesterday + 'T12:00:00',
end: yesterday + 'T12:40:00',
className: 'bg-success',
location: 'Diner',
description: 'Nam finibus felis hendrerit nibh vestibulum, vitae pellentesque leo sodales'
},
{
id: helper.setID(),
title: 'Scheduled server maintenance',
start: thisMonth + '27',
end: thisMonth + '29',
className: 'bg-danger',
description: 'Vestibulum maximus enim hendrerit molestie elementum'
}
]
});
calendarDraggable.render();
})();
}
Advanced (drag & drop, editable, external events)
Drag and drop your event or click in the calendar
Event
Event - Human Resource
Event - Meeting
Event - Important
<div class="row">
<div class="col-12 col-lg-4 col-xxl-3 mw-lg-300px">
<button class="btn btn-secondary w-100 mb-6" data-bs-toggle="modal" data-bs-target="#eventModal" id="btnAddEvent">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" height="14" width="14" class="me-1"><path d="M0,12a1.5,1.5,0,0,0,1.5,1.5h8.75a.25.25,0,0,1,.25.25V22.5a1.5,1.5,0,0,0,3,0V13.75a.25.25,0,0,1,.25-.25H22.5a1.5,1.5,0,0,0,0-3H13.75a.25.25,0,0,1-.25-.25V1.5a1.5,1.5,0,0,0-3,0v8.75a.25.25,0,0,1-.25.25H1.5A1.5,1.5,0,0,0,0,12Z" style="fill: currentColor"/></svg>
Add Event
</button>
<p class="fs-5 mb-4 text-secondary">
Drag and drop your event or click in the calendar
</p>
<div id="draggable">
<div class='fc-event fc-h-event fc-daygrid-event fc-daygrid-block-event text-bg-success-soft border-0 py-2 px-3 mb-3 cursor-move' data-class="bg-success border-0">
<span class='fc-event-main text-success'>Event</span>
</div>
<div class='fc-event fc-h-event fc-daygrid-event fc-daygrid-block-event text-bg-info-soft border-0 py-2 px-3 mb-3 cursor-move' data-class="bg-info border-0">
<span class='fc-event-main text-info'>Event - Human Resource</span>
</div>
<div class='fc-event fc-h-event fc-daygrid-event fc-daygrid-block-event text-bg-warning-soft border-0 py-2 px-3 mb-3 cursor-move' data-class="bg-warning border-0">
<span class='fc-event-main text-warning'>Event - Meeting</span>
</div>
<div class='fc-event fc-h-event fc-daygrid-event fc-daygrid-block-event text-bg-danger-soft border-0 py-2 px-3 mb-3 cursor-move' data-class="bg-danger border-0">
<span class='fc-event-main text-danger'>Event - Important</span>
</div>
</div>
</div>
<div class="col">
<div id="fullcalendar" class="h-1000px"></div>
</div>
</div>
// dashly/theme/src/js/vendors/fullcalendar.js
const calendarEl = document.getElementById('fullcalendar');
if(calendarEl) {
(async () => {
const {Calendar} = await import(/* webpackChunkName: 'fullcalendar.core' */ '@fullcalendar/core');
const [{default: dayGridPlugin}, {default: timeGridPlugin}, {default: listPlugin}, {default: interactionPlugin, Draggable}, {default: bootstrap5Plugin}, {default: moment}, helper] =
await Promise.all([
import(/* webpackChunkName: 'fullcalendar.daygrid' */ '@fullcalendar/daygrid'),
import(/* webpackChunkName: 'fullcalendar.timegrid' */ '@fullcalendar/timegrid'),
import(/* webpackChunkName: 'fullcalendar.list' */ '@fullcalendar/list'),
import(/* webpackChunkName: 'fullcalendar.interaction' */ '@fullcalendar/interaction'),
import(/* webpackChunkName: 'fullcalendar.bootstrap5' */ '@fullcalendar/bootstrap5'),
import(/* webpackChunkName: 'moment' */ 'moment'),
import(/* webpackChunkName: 'helpers' */ '../helpers')
]);
let draggableEl = document.getElementById('draggable'),
eventModal = document.getElementById('eventModal'),
eventModalEl = eventModal && new Modal(eventModal),
eventModalTitle = document.getElementById('eventModalTitle'),
eventForm = document.getElementById('eventForm'),
eventName = document.getElementById('eventName'),
startDate = document.getElementById('startDate'),
startTime = document.getElementById('startTime'),
endDate = document.getElementById('endDate'),
endTime = document.getElementById('endTime'),
location = document.getElementById('location'),
description = document.getElementById('description'),
allDayEvent = document.getElementById('allDayEvent'),
eventType = document.getElementById('eventType'),
btnSaveEvent = document.getElementById('btnSaveEvent'),
btnDeleteEvent = document.getElementById('btnDeleteEvent'),
btnAddEvent = document.getElementById('btnAddEvent'),
selectedEvent = null,
todayDate = moment().startOf('day'),
yesterday = todayDate.clone().subtract(1, 'day').format('YYYY-MM-DD'),
today = todayDate.format('YYYY-MM-DD'),
tomorrow = todayDate.clone().add(1, 'day').format('YYYY-MM-DD'),
thisMonth = todayDate.format('YYYY-MM'),
activeId = null;
let calendar = new Calendar(calendarEl, {
themeSystem: 'bootstrap5',
plugins: [dayGridPlugin, timeGridPlugin, listPlugin, interactionPlugin, bootstrap5Plugin],
initialView: 'dayGridMonth',
contentHeight: '100%',
headerToolbar: {
left: 'prev,next customToday',
center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek'
},
buttonText: {
today: 'Today',
month: 'Month',
week: 'Week',
day: 'Day',
list: 'List',
prev: 'Prev',
next: 'Next'
},
customButtons: {
customToday: {
text: 'Today',
click: () => {
calendar.today();
}
}
},
viewDidMount: () => {
calendarEl.querySelector('.fc-customToday-button').classList.add('btn-light');
},
eventClick: (arg) => {
eventModal && editEvent(arg);
},
slotDuration: '00:15:00',
slotMinTime: '08:00:00',
slotMaxTime: '19:00:00',
editable: true,
droppable: true,
dayMaxEvents: true,
events: [
{
id: helper.setID(),
title: 'Interview',
start: thisMonth + '05T10:30:00',
end: thisMonth + '05T13:30:00',
className: 'bg-info',
location: 'Room 127',
description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit'
},
{
id: helper.setID(),
title: 'Team building trip',
start: thisMonth + '15',
end: thisMonth + '18',
className: 'bg-success',
location: 'Florida',
description: 'Integer ullamcorper metus sed urna laoreet, sed convallis leo pretium'
},
{
id: helper.setID(),
title: 'Team meeting',
start: thisMonth + '25T13:15:00',
end: thisMonth + '25T15:00:00',
classNames: 'bg-warning',
location: 'Conference room',
description: 'Maecenas aliquam lectus ut nibh gravida egestas'
},
{
id: helper.setID(),
title: 'Seminarium',
start: today,
allDay: true,
className: 'bg-success',
location: 'Hall',
description: 'Mauris eu massa ac mauris dapibus consequat a at quam'
},
{
id: helper.setID(),
title: 'Front-End Interview',
start: yesterday + 'T09:00:00',
end: yesterday + 'T10:15:00',
location: 'Room 201',
description: 'Ut facilisis odio at lectus ultricies mattis. Morbi a arcu rhoncus ligula lobortis aliquet a in est'
},
{
id: helper.setID(),
title: 'Meeting',
start: yesterday + 'T10:30:00',
end: yesterday + 'T11:30:00',
className: 'bg-success',
location: 'Office',
description: 'Nunc quis augue non odio porttitor mattis'
},
{
id: helper.setID(),
title: 'Lunch',
start: yesterday + 'T12:00:00',
end: yesterday + 'T12:40:00',
className: 'bg-success',
location: 'Diner',
description: 'Nam finibus felis hendrerit nibh vestibulum, vitae pellentesque leo sodales'
},
{
id: helper.setID(),
title: 'Scheduled server maintenance',
start: thisMonth + '27',
end: thisMonth + '29',
className: 'bg-danger',
description: 'Vestibulum maximus enim hendrerit molestie elementum'
}
]
});
calendar.render();
if(draggableEl) {
new Draggable(draggableEl, {
itemSelector: '.fc-event',
eventData: (e) => {
return {
title: e.innerText,
className: e.dataset.class
};
}
});
}
let editEvent = (e) => {
selectedEvent = e.event;
activeId = selectedEvent ? selectedEvent.id : '';
eventForm.reset();
eventForm.classList.remove('was-validated');
btnDeleteEvent.style.display = 'block';
eventModalTitle.textContent = 'Edit Event';
eventModalEl.show();
eventName.value = selectedEvent.title;
eventType.value = selectedEvent.classNames[0];
selectedEvent.extendedProps.location ? location.value = selectedEvent.extendedProps.location : null;
selectedEvent.extendedProps.description ? description.value = selectedEvent.extendedProps.description : null;
selectedEvent.start ? startDate.value = moment(selectedEvent.start).format('MM/DD/YYYY') : null;
selectedEvent.start ? startTime.value = moment(selectedEvent.start).format('HH:mm') : null;
selectedEvent.end ? endDate.value = moment(selectedEvent.end).format('MM/DD/YYYY') : null;
selectedEvent.end ? endTime.value = moment(selectedEvent.end).format('HH:mm') : null;
allDayEvent.checked = selectedEvent.allDay;
showHideTimes();
// Retriving flatpickr and tomselect insctances to update values
let startDateFlatpickr = startDate._flatpickr,
endDateFlatpickr = endDate._flatpickr,
startTimeFlatpickr = startTime._flatpickr,
endTimeFlatpickr = endTime._flatpickr,
eventTypeSelect = eventType.tomselect;
startDateFlatpickr.setDate(startDate.value , true);
endDateFlatpickr.setDate(endDate.value, true);
startTimeFlatpickr.setDate(startTime.value , true);
endTimeFlatpickr.setDate(endTime.value, true);
eventTypeSelect.sync();
}
let newEvent = (e) => {
eventForm.reset();
eventForm.classList.remove('was-validated');
btnDeleteEvent.style.display = 'none';
eventModalTitle.textContent = 'Add New Event';
startDate.value = moment().format('MM/DD/YYYY');
endDate.value = moment().format('MM/DD/YYYY');
startTime.value = moment().format('HH:mm');
endTime.value = moment().format('HH:mm');
activeId = null;
// Retriving flatpickr and tomselect insctances to update values
let startDateFlatpickr = startDate._flatpickr,
endDateFlatpickr = endDate._flatpickr,
startTimeFlatpickr = startTime._flatpickr,
endTimeFlatpickr = endTime._flatpickr;
startDateFlatpickr.setDate(startDate.value, true);
endDateFlatpickr.setDate(endDate.value, true);
startTimeFlatpickr.setDate(startTime.value, true);
endTimeFlatpickr.setDate(endTime.value, true);
}
let createEvent = (e) => {
eventModalEl.hide();
calendar.addEvent({
id: helper.setID(),
title: eventName.value,
start: moment(new Date(startDate.value + ' ' + startTime.value)).toDate(),
end: moment(new Date(endDate.value + ' ' + endTime.value)).toDate(),
allDay: allDayEvent.checked,
className: eventType.value || 'bg-success',
location: location.value,
description: description.value
});
calendar.render();
eventForm.reset();
showHideTimes();
}
eventModal && allDayEvent.addEventListener('change', (e) => {
showHideTimes();
});
let showHideTimes = (e) => {
allDayEvent.checked ? startTime.parentNode.style.display = 'none' : startTime.parentNode.style.display = 'block';
allDayEvent.checked ? endTime.parentNode.style.display = 'none' : endTime.parentNode.style.display = 'block';
}
eventModal && btnSaveEvent.addEventListener('click', (e) => {
e.preventDefault();
activeId != null && removeEvent(activeId);
createEvent(e);
});
eventModal && btnAddEvent.addEventListener('click', (e) => {
e.preventDefault();
newEvent(e);
});
eventModal && btnDeleteEvent.addEventListener('click', (e) => {
e.preventDefault();
activeId != null && removeEvent(activeId);
});
function removeEvent(id) {
calendar.getEventById(id).remove();
}
})();
}