e8-calendar
Updated on Sep 18, 2025 82 minutes to readA flexible and feature-rich calendar component built.
It supports multiple views, event management (create, edit, delete), and customizable popups through slots.
Overview
e8-calendar provides an interactive scheduling interface with support for daily, weekly, monthly, yearly, and list views.
Users can navigate between periods, view events, and manage them with drag-and-drop, resizing, and inline editing.
Custom headers, action buttons, and event popups can be provided via slots for maximum flexibility.
Insert this code into Main or Initialization script of the form to register a global method
E8App.$set(E8App.vars, 'calendarEvents', [
{
id: 'allDay',
allDay: true,
startDate: E8App.$date.addDays(E8App.$date.current(), -1),
endDate: E8App.$date.addDays(E8App.$date.current(), -1),
title: 'All Day Conference',
description: 'A full-day event covering all key topics.',
backgroundColor: '#FF6B6B',
borderColor: '#FF3B3B',
},
{
id: 'todayEvent',
allDay: false,
startDate: E8App.$date.current(),
endDate: E8App.$date.current(),
startTime: '12:00:00',
endTime: '12:59:59',
title: 'Lunch Break',
description: 'Enjoy a relaxing lunch with colleagues.',
backgroundColor: '#4ECDC4',
borderColor: '#3BB6A5',
},
{
id: 'twoDayEvent',
allDay: false,
startDate: E8App.$date.current(),
endDate: E8App.$date.addDays(E8App.$date.current(), 1),
startTime: '13:00:00',
endTime: '18:00:00',
title: 'Tech Innovation Summit',
description: 'Two days of workshops and networking focused on technology trends.',
backgroundColor: '#FFD93D',
borderColor: '#FFC107',
},
{
id: 'morningMeeting',
allDay: false,
startDate: E8App.$date.current(),
endDate: E8App.$date.current(),
startTime: '09:00:00',
endTime: '10:00:00',
title: 'Morning Standup',
description: 'Daily team sync-up meeting.',
backgroundColor: '#6A4C93',
borderColor: '#5A3E7A',
},
{
id: 'eveningYoga',
allDay: false,
startDate: E8App.$date.current(),
endDate: E8App.$date.current(),
startTime: '19:00:00',
endTime: '20:00:00',
title: 'Evening Yoga',
description: 'Relax and unwind with a gentle yoga session.',
backgroundColor: '#FF8C42',
borderColor: '#E57200',
},
{
id: 'projectDeadline',
allDay: false,
startDate: E8App.$date.addDays(E8App.$date.current(), 2),
endDate: E8App.$date.addDays(E8App.$date.current(), 2),
startTime: '17:00:00',
endTime: '17:30:00',
title: 'Project Deadline',
description: 'Submit all deliverables for the project.',
backgroundColor: '#1FAB89',
borderColor: '#138A75',
},
{
id: 'teamBuilding',
allDay: true,
startDate: E8App.$date.addDays(E8App.$date.current(), 3),
endDate: E8App.$date.addDays(E8App.$date.current(), 3),
title: 'Team Building Day',
description: 'Outdoor activities designed to strengthen teamwork.',
backgroundColor: '#3A86FF',
borderColor: '#265DAB',
},
{
id: 'dentistAppointment',
allDay: false,
startDate: E8App.$date.addDays(E8App.$date.current(), 4),
endDate: E8App.$date.addDays(E8App.$date.current(), 4),
startTime: '14:30:00',
endTime: '15:30:00',
title: 'Dentist Appointment',
description: 'Routine dental check-up.',
backgroundColor: '#8338EC',
borderColor: '#5B24A6',
},
]);
Copy this snippet into the Content section
<e8-calendar
:events="vars.calendarEvents"
:popup-on-hover="true"
:height="500"
:year-view="true"
:sticky-header="true"
:sticky-header-dates="true"
min-time="09:00"
max-time="20:00"
year-view-variant="stack"></e8-calendar>
/>
Properties
| Property | Description | Type | Default |
|---|---|---|---|
| all-day | Enables or disables support for all-day events. | boolean | true |
| day-slot-height | Height of day slots. Applies only to the year or month view. | string | number | 'auto' |
| day-view | Enables daily view mode. | boolean | true |
| day-view-variant | Controls the layout of the day view. | E8CalendarDayViewVariants | 'time' |
| default-color | Default color applied to events without a specific color. | string | — |
| default-view | The initial calendar view. | E8CalendarViewVariants | 'week' |
| droppable | Allows external elements to be dropped onto the calendar as events. | boolean | true |
| event-display | Defines how events are displayed. | E8CalendarEventDisplaysVariants | 'block' |
| event-limit | Limits the number of events per day cell. | string | number | bool | true |
| events | Array of event objects rendered on the calendar. | Array<E8CalendarEvent> | [] |
| height | Calendar height (auto, number, or CSS string). | string | number | 'auto' |
| hidden-days | Array of weekday indices (0–6) to hide. | array | [] |
| list-view | Enables list view mode. | boolean | true |
| max-time | Defines the maximum visible time in a day. | E8Time | '24:00:00' |
| min-time | Defines the minimum visible time in a day. | E8Time | '00:00:00' |
| month-view | Enables monthly view mode. | boolean | true |
| popup-max-width | Maximum width of the event popup. | string | number | '25rem' |
| popup-min-width | Minimum width of the event popup. | string | number | — |
| popup-on-hover | Show popup on hover instead of click. | boolean | false |
| readonly | Disables event editing and drag-and-drop. | boolean | false |
| selectable | Allows selecting time ranges on the calendar. | boolean | true |
| sticky-header | Enables sticky positioning for the header. | boolean | false |
| sticky-header-dates | Makes header dates sticky during scrolling. | boolean | false |
| week-view | Enables weekly view mode. | boolean | true |
| week-view-variant | Controls the layout of the week view. | E8CalendarWeekViewVariants | 'time' |
| year-view | Enables yearly view mode. | boolean | false |
| year-view-variant | Controls the layout of the year view. | E8CalendarYearViewVariants | 'continuous' |
Slots
| Slot | Description |
|---|---|
| actions | Custom action buttons in the calendar header. |
| event | Custom rendering of an event inside the calendar. |
| popup-actions | Custom action buttons inside the event popup. |
| popup-title | Custom event title inside the popup. |
| popup-range | Custom event date/time range inside the popup. |
| popup-description | Custom event description inside the popup. |
Events
| Event | Description | Arguments (in order) |
|---|---|---|
| on-change-event | Called after a drag or resize, before on-drop-event or on-resize-event. Receives a new object with the event ID and updated range. | eventData: object (event id and updated range fields) |
| on-change-period | Called when the visible calendar range is set, including initial rendering and navigation. | startDate: E8Date, endDate: E8Date, start: E8Timestamp, end: E8Timestamp |
| on-copy-event | Called when the Copy action is selected. The handler creates the copy and updates events. | eventData: E8CalendarEvent |
| on-delete-event | Called when the Delete action is selected. The handler deletes the event and updates events. | eventData: E8CalendarEvent |
| on-drop-event | Called after an existing event is dragged to a new date or time. Receives the original event followed by the new range. | eventData: E8CalendarEvent, allDay: boolean, startDate: E8Date, endDate: E8Date, startTime: E8Time | undefined, endTime: E8Time | undefined, start: E8Timestamp | E8Date, end: E8Timestamp | E8Date |
| on-edit-event | Called on an event double-click or the Edit action. The handler opens the editor. | eventData: E8CalendarEvent |
| on-render-day-slot | Called when a day slot is mounted. The handler may change slotData.backgroundColor or style el. | slotData: object (start/end dates, times and timestamps, allDay, backgroundColor), el: HTMLElement |
| on-render-event | Called when an event element is mounted. Receives the original event and its element for customization. | eventData: E8CalendarEvent, el: HTMLElement |
| on-resize-event | Called after an event is resized. Receives the original event followed by the new range. | eventData: E8CalendarEvent, allDay: boolean, startDate: E8Date, endDate: E8Date, startTime: E8Time | undefined, endTime: E8Time | undefined, start: E8Timestamp | E8Date, end: E8Timestamp | E8Date |
| on-select-range | Called when a date or time range is selected. For all-day ranges, times are undefined and start/end are dates. | allDay: boolean, startDate: E8Date, endDate: E8Date, startTime: E8Time | undefined, endTime: E8Time | undefined, start: E8Timestamp | E8Date, end: E8Timestamp | E8Date |
Properties Details
All Day Events
Enables all-day slot display for events. This slot is only visible in day and week views.
Default: true
Day Slot Height
Sets a fixed height for each day slot in the calendar. Applied only in year and month views.
Accepted values include numeric values (pixels), CSS length units (e.g., "100px", "2rem"), or "auto" to let the slot height adjust automatically.
Default: 'auto'
Day View
Show day view button in the calendar toolbar.
Default: true
Day View Variant
Variant of day view.
Default: 'time'
Default Color
Default color used for events without specified colors. Accepts HEX codes or CSS color names.
Default: ''
Default View
Initial calendar view.
Default: 'timeGridWeek'
Droppable
Allows external events to be dropped onto the calendar.
Default: true
⚠️ Only events that extend the E8CalendarEvent object format are supported.
Event Display
Display mode for events.
Default: 'block'
E8App.vars.displayEvents = [
{
id: 1,
title: 'Event',
startDate: E8App.$date.addDays(E8App.$date.current(), -1),
endDate: E8App.$date.addDays(E8App.$date.current(), -1),
startTime: '11:00:00',
endTime: '13:00:00',
}
];
Event Limit
Controls how many events are displayed per day before showing a “+N more” link in month or week views:
- true — uses the default limit defined by the calendar (automatically determined by the cell height).
- false — do not limit events; all events are shown.
- number — show up to that many events per day, excess events will be hidden under the “+N more” link.
- string — numeric values as string (e.g., "3") are treated as a number limit.
Default : true
E8App.vars.limitEvents = Array.from({ length: 23 }, (_, i) => {
let date = E8App.$date.current();
if (i % 2 === 0) {
date = E8App.$date.addDays(date, -1)
}
if (i % 3 === 0) {
date = E8App.$date.addDays(date, 1)
}
if (i % 5 === 0) {
date = E8App.$date.addWeeks(date, -1)
}
return {
id: i,
title: `Event ${i}`,
startDate: date,
endDate: date,
startTime: `${i < 10 ? '0' + i : i}:00:00`,
endTime: `${i < 10 ? '0' + i : i}:59:59`,
}
});
Events
An array of objects that extend the E8CalendarEvent interface, rendered in the calendar.
Default: []
Hidden Days
Array of days to hide in the calendar. 0 = Sunday, 6 = Saturday.
Default: []
Height
Calendar height. Can be 'auto' or a fixed value (pixels or CSS units)
Default: 'auto'
List View
Show list view button in the calendar toolbar.
Default: true
Max Time
Maximum time displayed in time grid views.
Default: '24:00:00'
Min Time
Minimum time displayed in time grid views.
Default: '00:00:00'
Month View
Show month view button in the calendar toolbar.
Default: true
Popup Max Width
Maximum width of event popup. Can be pixels, rem, or other CSS units.
Default: '25rem'
Popup Min Width
Minimum width of event popup. Can be pixels, rem, or other CSS units.
Default: ''
Popup On Hover
Show event popup on hover instead of click.
Default: false
Readonly
Makes all events read-only and disables editing.
Default: false
Selectable
Enables selecting date or time ranges directly on the calendar by dragging or clicking.
When selectable is true, users can select a range of dates (or hours in day/week views), and the on-select-range event will be triggered with details about the selected start and end.
This is useful for creating new events, highlighting periods, or implementing custom actions when a range is selected.
Default: false
Sticky Header
Enables a sticky header for the calendar.
When sticky-header is true, the top part of the calendar containing action buttons (view switches, today/prev/next buttons, etc.) and the date headers remain fixed when scrolling through the calendar content.
This ensures that controls and dates are always visible even when viewing long lists of events or month/day grids.
Default: false
⚠️ When sticky-header is true, it automatically includes sticky behavior for the dates, so sticky-header-dates does not need to be enabled separately.
Sticky Header Dates
Enables a sticky header specifically for the date row(s) in month and week views.
When sticky-header-dates is true and sticky-header is not enabled, the date labels at the top of the calendar grid remain visible while scrolling.
Default: false
⚠️ If sticky-header is true, sticky-header-dates is automatically applied and does not need to be set.
Week View
Show week view button in the calendar toolbar.
Default: true
Week View Variant
Variant of week view.
Default: 'time'
Year View
Show year view button in the calendar toolbar.
Default: false
Year View Variant
Variant of year view.
Default: 'continuos'
Events Details
Event: On Change Event
Called when an existing event is moved or resized.
Receives a new eventData object containing id, allDay, startDate, endDate, start, and end. Timed events also include startTime and endTime. This is a change payload, not the original object from events.
For all-day events, start and end are dates, and endDate is the inclusive last day. For timed events, start and end are timestamps. Use this payload to update the corresponding event in your data.
Insert this code into Main or Initialization script of the form to register a global method
E8App.$methods.set('onChangeEvent', (eventData) => {
console.log('Updated event:', eventData)
});
Copy this snippet into the Content section
<e8-calendar
:events="vars.calendarEvents"
on-change-event="onChangeEvent"
></e8-calendar>
Event: On Change Period
Called when the visible period is set, including initial rendering and navigation to another week or month.
endDate is the inclusive last visible day, and end is the end of that day. Receives four arguments:
startDate— visible range start as E8DateendDate— visible range end as E8Datestart— visible range start as E8Timestampend— visible range end as E8Timestamp
Insert this code into Main or Initialization script of the form to register a global method
E8App.$methods.set('onChangePeriod', (startDate, endDate, start, end) => {
console.log('Visible period:', startDate, endDate, start, end);
});
Copy this snippet into the Content section
<e8-calendar
on-change-period="onChangePeriod"
></e8-calendar>
Event: On Copy Event
Called when the event’s Copy action is selected. Receives the original event object from events.
The handler creates the new event and updates application data; the component does not create a copy automatically.
Insert this code into Main or Initialization script of the form to register a global method
E8App.$methods.set('onCopyEvent', (eventData) => {
console.log('Copy requested:', eventData);
});
Copy this snippet into the Content section
<e8-calendar
:events="vars.calendarEvents"
on-copy-event="onCopyEvent"
></e8-calendar>
Event: On Delete Event
Called when the event’s Delete action is selected.
Receives the original eventData object from events. The handler must delete the event from application data and update events; the callback itself does not remove it.
Insert this code into Main or Initialization script of the form to register a global method
E8App.$methods.set('onDeleteEvent', (eventData) => {
console.log('Delete requested:', eventData);
});
Copy this snippet into the Content section
<e8-calendar
:events="vars.calendarEvents"
on-delete-event="onDeleteEvent"
></e8-calendar>
Event: On Drop Event
Called after an existing calendar event is dragged to a new date or time, following on-change-event.
Receives the original event object followed by allDay, startDate, endDate, startTime, endTime, start, and end. Use these range arguments for the new position; the original event object is not rewritten by this callback.
Insert this code into Main or Initialization script of the form to register a global method
E8App.$methods.set('onDropEvent', (eventData, allDay, startDate, endDate, startTime, endTime, start, end) => {
console.log('Moved event:', eventData.id, { allDay, startDate, endDate, startTime, endTime, start, end });
});
Copy this snippet into the Content section
<e8-calendar
:events="vars.calendarEvents"
on-drop-event="onDropEvent"
></e8-calendar>
Event: On Edit Event
Called when an event is double-clicked or its Edit action is selected.
Receives the original eventData object from events. The handler opens the editing interface and applies any saved changes.
Insert this code into Main or Initialization script of the form to register a global method
E8App.$methods.set('onEditEvent', (eventData) => {
console.log('Edit event:', eventData)
});
Copy this snippet into the Content section
<e8-calendar
:events="vars.calendarEvents"
on-edit-event="onEditEvent"
></e8-calendar>
Event: On Render Day Slot
Called when a day slot is mounted. Receives slotData and the slot element el.
slotData contains startDate, endDate, startTime, endTime, start, end, allDay, and backgroundColor. Its range spans that day, and allDay is true.
Use this callback to customize the appearance of specific days.
Two main options are available:
1️⃣ Set the background color by changing slotData.backgroundColor synchronously.
Insert this code into Main or Initialization script of the form to register a global method
E8App.$methods.set('onRenderDaySlot', (eventData, el) => {
if (E8App.$date.day(eventData.stardDate) % 2) {
eventData.backgroundColor = 'salmon';
}
});
Copy this snippet into the Content section
<e8-calendar
on-render-day-slot="onRenderDaySlot"
></e8-calendar>
2️⃣ Modify the supplied element el, for example by adding classes, styles, or attributes.
Insert this code into Main or Initialization script of the form to register a global method
E8App.$methods.set('onRenderDaySlot', (eventData, el) => {
if (E8App.$date.day(eventData.stardDate) % 2) {
info.el.style.backgroundColor = 'salmon';
}
});
Copy this snippet into the Content section
<e8-calendar
on-render-day-slot="onRenderDaySlot"
></e8-calendar>
Event: Render Event
Called when an event element is mounted.
Receives the original eventData object from events and the rendered element el. The callback does not replace the event’s dates or times; use el to customize its appearance.
You can:
- Apply inline styles
- Add or remove CSS classes
- Insert additional child elements
- Customize the structure or attributes of the event node
This provides full control over the visual presentation of events beyond what props and slots allow.
Insert this code into Main or Initialization script of the form to register a global method
E8App.$methods.set('onRenderEvent', (eventData, el) => {
if (eventData.startDate < E8App.$date.current()) {
el.style.border = '2px solid gold'
el.style.padding = '4px'
// Add custom icon inside the event element
const icon = document.createElement('i')
icon.className = 'e8i e8i-star-fill'
icon.style.marginRight = '4px'
el.prepend(icon)
}
});
Copy this snippet into the Content section
<e8-calendar
:events="vars.calendarEvents"
on-render-event="onRenderEvent"
></e8-calendar>
Event: On Resize Event
Called after an event is resized, following on-change-event.
Receives the original event object followed by allDay, startDate, endDate, startTime, endTime, start, and end. These separate range arguments describe the new duration.
E8App.$methods.set('onResizeEvent', (eventData, allDay, startDate, endDate, startTime, endTime, start, end) => {
console.log('Resized event:', eventData.id, { allDay, startDate, endDate, startTime, endTime, start, end });
});
Copy this snippet into the Content section
<e8-calendar
:events="vars.calendarEvents"
on-resize-event="onResizeEvent"
></e8-calendar>
Insert this code into Main or Initialization script of the form to register a global method
Event: On Select Range
Triggered when the user selects a date or time range on the calendar (via click or drag).
Receives seven arguments in order: allDay, startDate, endDate, startTime, endTime, start, and end.
For an all-day selection, startTime and endTime are undefined, start and end are dates, and endDate is inclusive. For a timed selection, the times are supplied and start/end are timestamps. Use these values to create an event or highlight the selection.
Insert this code into Main or Initialization script of the form to register a global method
E8App.$methods.set('onSelectRange', (allDay, startDate, endDate, startTime, endTime, start, end) => {
console.log('Selected range:', { allDay, startDate, endDate, startTime, endTime, start, end });
});
Copy this snippet into the Content section
<e8-calendar
on-select-range="onSelectRange"
></e8-calendar>
Slots Details
Slot: Actions
Slot for rendering custom action buttons in the calendar header (next to the "Today" and navigation buttons).
<e8-calendar height="100px">
<template #actions>
<e8-button variant="success" size="small">Custom Action</e8-button>
</template>
</e8-calendar>
Slot: Event
Custom slot for rendering event content inside the calendar.
Receives event argument, which corresponds to eventData from the provided events array.
<e8-calendar
height="300px"
:events="vars.calendarEvents"
>
<template #event="{ event }">
<div>
<strong>{{ event.title }}</strong>
<small>{{ event.description }}</small>
</div>
</template>
</e8-calendar>
Slot: Popup Actions
Custom slot for rendering event content inside the calendar.
Receives event argument, which corresponds to eventData from the provided events array.
<e8-calendar
height="300px"
:events="vars.calendarEvents"
>
<template #popup-actions="{ event }">
<e8-button size="small">Custom</e8-button>
</template>
</e8-calendar>
Slot: Popup Title
Slot for customizing the event title inside the popup.
Receives event argument, which corresponds to eventData from the provided events array.
{{ event.title }}
<e8-calendar
height="300px"
:events="vars.calendarEvents"
>
<template #popup-title="{ event }">
<h4 style="color: salmon">{{ event.title }}</h4>
</template>
</e8-calendar>
Slot: Popup Description
Slot for customizing the event description inside the popup.
Receives event argument, which corresponds to eventData from the provided events array.
{{ event.description || 'No description' }}
<e8-calendar
height="300px"
:events="vars.calendarEvents"
>
<template #popup-description="{ event }">
<p style="white-space: pre-line; color: gray">
{{ event.description || 'No description' }}
</p>
</template>
</e8-calendar>
Slot: Popup Range
Slot for customizing the event date/time range inside the popup.
Receives event argument, which corresponds to eventData from the provided events array.
<e8-calendar
height="300px"
:events="vars.calendarEvents"
>
<template #popup-range="{ event }">
<span>🗓 {{ event.startDate }} → {{ event.endDate }}</span>
</template>
</e8-calendar>