Calendar
CoolAdmin's calendar page uses FullCalendar 6.1.20 with four views (Month / Week / Day / List) and a self-updating event generator — every page load spreads ~20 events across the current month so the demo never goes stale.
Last updated May 22, 2026
The calendar page (calendar.html) is a working FullCalendar 6.1.20 instance with four built-in views (Month, Week, Day, List), event color-coding by tag, and a deadline list pane next to the grid.
The clever bit: events aren’t a static array. The page generates events relative to today on every load, so whether you open the demo in May 2026 or March 2030, the month always looks populated with past, present, and upcoming events.
Where the code lives
FullCalendar is loaded as a vendor script on the calendar page only — not on every page in the template. CoolAdmin doesn’t ship a chart factory file for FullCalendar like it does for Chart.js; the calendar’s init is an inline <script> at the bottom of calendar.html.
<!-- calendar.html — only this page loads FullCalendar -->
<link href="vendor/fullcalendar/main.css-6.1.20.min.css" rel="stylesheet">
<script src="vendor/fullcalendar/main.js-6.1.20.min.js"></script>
<!-- …page markup… -->
<script>
document.addEventListener('DOMContentLoaded', function () {
const calendarEl = document.getElementById('calendar');
if (!calendarEl) return;
const events = buildEvents(new Date());
renderDeadlineList(events);
const calendar = new FullCalendar.Calendar(calendarEl, {
initialView: 'dayGridMonth',
headerToolbar: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek'
},
height: 'auto',
events: events,
eventDisplay: 'block',
displayEventTime: true,
dayMaxEvents: 3,
moreLinkText: 'more',
navLinks: true,
nowIndicator: true,
eventTimeFormat: { hour: 'numeric', minute: '2-digit', meridiem: 'short' },
eventClick: (info) => { /* …open detail modal… */ },
windowResize: () => calendar.updateSize()
});
calendar.render();
window.calendarInstance = calendar;
});
</script>
The instance is parked on window.calendarInstance so other scripts (debug tools, custom integrations) can reach into it for calendar.addEvent(), calendar.refetchEvents(), etc.
The self-updating event generator
A buildEvents(today) function takes the current date and returns an array of ~20 events spread across that month — past, present, and future. The strategy:
function buildEvents(today) {
const y = today.getFullYear();
const m = today.getMonth();
// Helpers
const ymd = (d) => `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}-${String(d.getDate()).padStart(2,'0')}`;
const ymdt = (d, h, mm) => ymd(d) + 'T' + `${String(h).padStart(2,'0')}:${String(mm||0).padStart(2,'0')}:00`;
const offset = (n) => { const d = new Date(today); d.setDate(today.getDate() + n); return d; };
const nthDow = (n, dow) => { /* nth occurrence of weekday `dow` in this month */ };
const lastDow = (dow) => { /* last occurrence of weekday `dow` in this month */ };
return [
// …weekly recurring items (every Monday standup, every Friday demo)
// …date-relative anchors (offset(-3) for "three days ago", offset(+7) for "next week")
// …calendar-anchored events (nthDow(2, 1) for "second Monday of the month")
];
}
The function returns event objects in FullCalendar’s standard shape:
{
title: 'Standup',
start: ymdt(monday, 9, 30),
end: ymdt(monday, 10),
extendedProps: { type: 'meeting', owner: 'You' }
}
The extendedProps field carries per-event metadata (tag type, owner, location) that the click handler uses to populate the detail modal — and the deadline list pane uses for icons and color coding.
Event color coding
Events are tagged by type in their extendedProps. The CSS classes are wired in _pages.scss based on a TAG_COLORS map in the inline script:
const TAG_COLORS = {
meeting: { bg: '#eaf0fc', fg: '#4272d7' }, /* brand blue */
task: { bg: '#e0f3f1', fg: '#0d8780' }, /* teal */
deadline: { bg: '#fef2f2', fg: '#ef4444' }, /* danger red */
personal: { bg: '#fef3c7', fg: '#d97706' }, /* amber */
social: { bg: '#ede9fe', fg: '#7c3aed' }, /* purple */
travel: { bg: '#fce7f3', fg: '#be185d' } /* pink */
};
To add a new tag color: append to TAG_COLORS and emit a matching CSS class in _pages.scss.
The deadline list pane
The right-side panel shows the next upcoming events in a sorted list. Built by renderDeadlineList(events):
- Filters events to those starting today or later
- Sorts by start time
- Takes the first 6
- Renders each as a card with date, time, title, and a colored tag
This is a separate static render — it doesn’t update when the user navigates the calendar to a different month. For that behavior, hook FullCalendar’s datesSet callback and re-render the list from calendar.getEvents().
Switching views
The header toolbar exposes four view buttons that ship with FullCalendar:
| Button | View key | What it shows |
|---|---|---|
| Month | dayGridMonth | 6-week grid (the default) |
| Week | timeGridWeek | Hour-granular columns for the week |
| Day | timeGridDay | Hour-granular column for one day |
| List | listWeek | Flat list of the week’s events |
Default is Month. Change the initial view by editing initialView in the config:
const calendar = new FullCalendar.Calendar(calendarEl, {
initialView: 'timeGridWeek', // ← was 'dayGridMonth'
// …
});
Adding a real event source
The demo uses inline-generated events. To wire it to a backend, swap the events option to a function or URL:
const calendar = new FullCalendar.Calendar(calendarEl, {
initialView: 'dayGridMonth',
events: async (info, successCallback, failureCallback) => {
try {
const r = await fetch(`/api/events?start=${info.startStr}&end=${info.endStr}`);
const data = await r.json();
successCallback(data);
} catch (e) {
failureCallback(e);
}
}
});
FullCalendar calls the function every time the visible date range changes (next/prev/today, view switch). Your API returns events in the same shape: { title, start, end?, allDay?, extendedProps?: {} }.
See the FullCalendar event sources docs for the full schema.
Why FullCalendar and not a custom calendar
FullCalendar gets four things almost for free:
- All four views (Month / Week / Day / List) wired and styled
- Navigation toolbar with prev/next/today and view switcher
- Click + drag interactions for resizing events, moving them between days, picking a date
- Accessibility — keyboard navigation, ARIA labels, focus management
Writing those from scratch is a multi-week project. FullCalendar in CoolAdmin is just a vendored script + ~50 lines of init.
The cost is ~80 KB of FullCalendar JS + CSS, loaded only on the calendar page. That’s a one-page tax, not a template-wide cost.
See also
- Charts — the other major library integration
- Architecture — page-specific vendor scripts pattern
- Interactive components — inbox, kanban, data table (the rest of the live UI demos)