
The calendar works as a standalone module with zero dependencies. You can use it with JavaScript modules, Svelte components, or a standalone browser bundle.
Features:
- Minimal DOM structure using CSS Grid layout.
- Full drag and drop support for events and resizing.
- Multiple view types, including day grid, time grid, list, and resource timeline.
- Resource view support with nested resources and expand/collapse functionality.
- Timeline views for horizontal time axis display.
- Event filtering and ordering capabilities.
- Customizable button toolbar with built-in navigation controls.
- Date selection with configurable constraints.
- All-day slot support with customizable display.
- Week number display with ISO or Western system options.
- Popover display for days with too many events.
- Built-in dark theme with CSS variable customization.
- Touch device support with configurable long-press delays.
- Asynchronous event fetching from URLs or custom functions.
- Resource fetching with date range parameters.
- Method API for programmatic control.
Use Cases:
- Build a booking system for appointments with resource allocation across multiple staff members.
- Create a project management dashboard showing tasks across different team members or departments.
- Develop an event scheduling tool that requires both timeline and grid views for different planning needs.
- Implement a resource calendar for equipment or room reservations with nested resource hierarchies.
How to use it:
1. Install and import EventCalendar with NPM. The npm package requires at least one view plugin. The available view plugins are: DayGrid, List, ResourceTimeline, ResourceTimeGrid, TimeGrid, and Interaction. The Interaction plugin adds drag-and-drop and date selection but does not provide a view on its own. Import the plugins you need alongside createCalendar.
# NPM $ npm install @event-calendar/core
import { createCalendar, destroyCalendar, TimeGrid } from '@event-calendar/core';
// Import the stylesheet if your build tool supports CSS imports
import '@event-calendar/core/index.css';2. You can also include the standalone bundle directly in your HTML document.
<link rel="stylesheet" href="/dist/event-calendar.min.css"> <script src="/dist/event-calendar.min.js"></script> <!-- Or from a CDN --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@event-calendar/build@latest/dist/event-calendar.min.css"> <script src="https://cdn.jsdelivr.net/npm/@event-calendar/build@latest/dist/event-calendar.min.js"></script>
3. Create a basic event calendar.
<div id="team-schedule"></div>
// Mount the calendar to a DOM element with id="team-schedule"
let ec = createCalendar(
document.getElementById('team-schedule'),
// Pass an array of view plugins — at least one is required
[TimeGrid],
{
view: 'timeGridWeek', // Start in weekly time grid view
firstDay: 1, // 1 = Monday as the first day of the week
scrollTime: '08:00:00', // Scroll the time axis to 8 AM on initial render
nowIndicator: true, // Show a line marking the current time
events: [
{
id: 'standup-1',
title: 'Team Standup',
start: '2026-04-07 09:00:00',
end: '2026-04-07 09:30:00'
},
{
id: 'review-2',
title: 'Design Review',
start: '2026-04-08 14:00:00',
end: '2026-04-08 16:00:00',
backgroundColor: '#2c7be5', // Per-event background color override
textColor: '#ffffff'
}
]
}
);
// Destroy the calendar instance when you no longer need it
destroyCalendar(ec);// Standalone Bundle Setup
let ec = EventCalendar.create(document.getElementById('team-schedule'), {
// ...
}4. Drag-and-Drop with Resource Views:
import { createCalendar, ResourceTimeGrid, Interaction } from '@event-calendar/core';
import '@event-calendar/core/index.css';
let ec = createCalendar(
document.getElementById('staff-schedule'),
// ResourceTimeGrid provides the view; Interaction adds drag-and-drop
[ResourceTimeGrid, Interaction],
{
view: 'resourceTimeGridDay',
editable: true, // Enables drag-and-drop and resize for all events
resources: [
{ id: 'r-alice', title: 'Alice Chen' },
{ id: 'r-bob', title: 'Bob Martinez' },
{ id: 'r-carol', title: 'Carol Patel' }
],
events: [
{
id: 'appt-101',
resourceId: 'r-alice', // Associates this event with Alice's column
title: '1:1 Performance Review',
start: '2026-04-07 10:00:00',
end: '2026-04-07 10:45:00'
},
{
id: 'appt-102',
resourceId: 'r-bob',
title: 'Client Onboarding Call',
start: '2026-04-07 11:00:00',
end: '2026-04-07 12:30:00',
backgroundColor: '#e67e22'
},
{
// resourceIds (plural) assigns one event to multiple resources
id: 'appt-103',
resourceIds: ['r-alice', 'r-carol'],
title: 'Shared Workshop',
start: '2026-04-07 14:00:00',
end: '2026-04-07 15:30:00'
}
],
eventDrop: function(info) {
// Fires after a successful drop at a new date/time or resource
// info.event reflects the updated state; info.oldEvent holds the previous state
// Call info.revert() to cancel the move programmatically
console.log(info.event.title + ' dropped to', info.event.start);
if (info.newResource) {
console.log('New resource:', info.newResource.title);
}
},
eventResize: function(info) {
// Fires after the user extends or shortens an event by dragging its edge
console.log('Updated end time:', info.event.end);
// Call info.revert() to cancel the resize
},
dragConstraint: function(info) {
// Return false to block a drop into specific time slots
// info contains the same properties as eventDrop
let hour = info.event.start.getHours();
return hour >= 8 && hour < 18; // Restrict drops to business hours only
}
}
);5. Fetching Events from a URL:
let ec = createCalendar(
document.getElementById('team-schedule'),
[TimeGrid],
{
view: 'timeGridWeek',
// eventSources replaces the events array when remote data is needed
eventSources: [
{
url: '/api/calendar/events', // EventCalendar appends ?start=...&end=...
method: 'GET',
extraParams: {
// Pass any additional query parameters here
projectId: 101,
timezone: 'America/New_York'
}
}
],
loading: function(isLoading) {
// isLoading is true when fetching begins, false when it completes
document.getElementById('calendar-spinner').style.display =
isLoading ? 'flex' : 'none';
}
}
);
// Manually trigger a refetch when your data changes on the server
ec.refetchEvents();6. You can also pass an async function as the event source if you need custom fetch logic:
eventSources: [
{
events: async function(fetchInfo, successCallback, failureCallback) {
// fetchInfo.start and fetchInfo.end are Date objects for the visible range
try {
const res = await fetch(
`/api/events?from=${fetchInfo.startStr}&to=${fetchInfo.endStr}`
);
const data = await res.json();
successCallback(data); // Pass the event array to the calendar
} catch (err) {
failureCallback(err); // Signal the failure to the calendar
}
}
}
]7. Modifying Options at Runtime:
// Read the current value of any option
let activeView = ec.getOption('view');
let currentDate = ec.getOption('date');
// Update any option — the calendar re-renders to reflect the change immediately
ec.setOption('view', 'dayGridMonth');
ec.setOption('date', new Date('2026-07-01'));
ec.setOption('slotDuration', '00:15:00'); // Switch from 30-min to 15-min time slots
// setOption returns the calendar instance for chaining
ec.setOption('firstDay', 1).setOption('slotHeight', 32);8. All configuration options:
Display and Layout
-
view(string): The active calendar view. Options:'dayGridDay','dayGridWeek','dayGridMonth','listDay','listWeek','listMonth','listYear','resourceTimeGridDay','resourceTimeGridWeek','resourceTimelineDay','resourceTimelineWeek','resourceTimelineMonth','resourceTimelineYear','timeGridDay','timeGridWeek'. Default:'timeGridWeek'. -
views(object): Per-view option overrides and custom view definitions. Use thetypeproperty to inherit from a standard view. -
date(Date | string): The date currently displayed on the calendar. Accepts a JavaScript Date object or an ISO8601 string. Default:new Date(). -
duration(string | integer | object): The duration of a view, parsed as a Duration object. Default varies by view. -
height(string): The height of the entire calendar as a CSS value, e.g.'600px'or'100%'. -
headerToolbar(object): Toolbar layout defined withstart,center, andendstring properties. Values separated by commas render adjacently; values separated by spaces render with a small gap. Default:{start: 'title', center: '', end: 'today prev,next'}. -
buttonText(object | function): Text labels for toolbar navigation buttons. -
customButtons(object | function): Custom button definitions for placement in the header toolbar. Each entry takestext,click, andactiveproperties. -
customScrollbars(boolean): Enables styled scrollbars in supported browsers. Default:false. -
columnWidth(string): Column width intimeGridandresourceTimeGridviews as a CSS length value. -
slotDuration(string | integer | object): Frequency of displayed time slots, parsed as a Duration object. Default:'00:30:00'. -
slotHeight(integer): Height in pixels of each time slot row intimeGridviews. Default:24. -
slotWidth(integer): Width in pixels of each time slot column inresourceTimelineviews. Default:32. -
slotMinTime(string | integer | object): The first time slot displayed for each day, parsed as a Duration object. Default:'00:00:00'. -
slotMaxTime(string | integer | object): The last time slot displayed for each day, parsed as a Duration object. Default:'24:00:00'. -
slotLabelFormat(object | function): Format of text labels inside time slots. -
slotLabelInterval(string | integer | object): Interval at which slot labels appear, parsed as a Duration object. -
slotEventOverlap(boolean): Controls whether intersecting events visually overlap intimeGridviews. Set tofalseto render them side-by-side. Default:true. -
scrollTime(string | integer | object): Initial scroll position in the time grid, parsed as a Duration object. Default:'06:00:00'. -
snapDuration(string | integer | object): Step size for dragging, resizing, and selection on the time axis. Defaults toslotDurationwhen not specified. -
nowIndicator(boolean): Displays a current-time marker line intimeGridviews. Default:false. -
firstDay(integer): First day of the week. Sunday =0, Monday =1, Saturday =6. Default:0. -
hiddenDays(array): Array of day-of-week integers to exclude from the calendar display. -
highlightedDates(array): An array of ISO8601 date strings or JavaScript Date objects to highlight on the calendar. -
weekNumbers(boolean): Shows week numbers indayGridandresourceTimelineviews. Default:false. -
weekNumberContent(Content | function): Custom content for week number cells. -
dayMaxEvents(boolean): Limits stacked event levels per day indayGridviews, showing a “+N more” link for overflow. Default:false. -
moreLinkContent(Content | function): Custom content for the “+N more” overflow link. -
dayPopoverFormat(object | function): Format of the popover title shown by the “+N more” link. Default:{month: 'long', day: 'numeric', year: 'numeric'}. -
validRange(object): Restricts calendar navigation to a date range usingstartandendproperties. Either property is optional. -
locale(string): The locale string passed toIntl.DateTimeFormatfor all date and time formatting. -
theme(object | function): CSS class name mappings for every calendar element. -
flexibleSlotTimeLimits(boolean | object): Automatically expandsslotMinTimeandslotMaxTimewhen events fall outside the visible time range. Default:false. -
pointer(boolean): Enables a pointer cursor style in applicable views. RequiresInteractionplugin. Default:false.
Duration Object Reference
Duration objects store time periods like 30 minutes or 3 days. Input values parse from three formats: an object with keys years, months, days, hours, minutes, or seconds; a string in hh:mm:ss or hh:mm format; or an integer representing total seconds.
Events
-
events(array): An array of plain event objects to display. Ignored wheneventSourcesis set. Default:[]. -
eventSources(EventSource[]): Event source definitions for URL fetching or custom async functions. Each source can include aurl,method, andextraParamsfor HTTP fetching, or aneventsfunction for custom logic. -
lazyFetching(boolean): Fetches events only when the calendar needs data for a date range it has not yet cached. Default:true. -
eventBackgroundColor(string): Default background color for all calendar events. -
eventTextColor(string): Default text color for all calendar events. -
eventColor(string): Alias foreventBackgroundColor. -
eventClassNames(string | array | function): Additional CSS classes applied to event elements. -
eventContent(Content | function): Custom content rendered inside each event element. -
eventDidMount(function): Fires immediately after an event element is inserted into the DOM. -
eventTimeFormat(object | function): Format of the time text displayed on each event. Default:{hour: 'numeric', minute: '2-digit'}. -
displayEventEnd(boolean): Controls whether an event’s end time renders on the event. Default varies by view. -
eventOrder(function): Comparator function for ordering visually intersecting events. Return negative, zero, or positive values. -
eventFilter(function): Filter function applied to the event array before display. Returntrueto keep an event,falseto hide it. -
eventAllUpdated(function): Fires after all events complete a full re-render cycle.
When parsing events from plain objects, EventCalendar accepts the following fields:
-
id(string | integer): A unique identifier for the event. Auto-generated if omitted. -
title(Content): The text displayed on the event element. -
start(string | Date): Event start time as an ISO8601 string or Date object. -
end(string | Date): Event end time as an ISO8601 string or Date object. -
allDay(boolean): Forces the event into the all-day slot. Auto-detected from thestartvalue when not specified. -
resourceIdorresourceIds(string | integer | array): The resource ID or array of IDs this event belongs to. -
editable(boolean): Per-event override for the globaleditablesetting. -
startEditable(boolean): Per-event override for drag permission. -
durationEditable(boolean): Per-event override for resize permission. -
display(string): Rendering mode. Use'auto'for standard events or'background'for background highlights. -
backgroundColor(string): Per-event background color as any CSS color value. -
textColor(string): Per-event text color as any CSS color value. -
color(string): Alias forbackgroundColor. -
classNamesorclassName(string | array): Additional CSS classes for this event. -
stylesorstyle(string | array): Additional inline style declarations for this event. -
extendedProps(object): A plain object for any custom properties. Accessible atevent.extendedPropsin callbacks.
Interaction
-
editable(boolean): Enables drag-and-drop and resize for all events. RequiresInteractionplugin. Default:false. -
eventStartEditable(boolean): Controls whether events can be repositioned by dragging. RequiresInteractionplugin. Default:true. -
eventDurationEditable(boolean): Controls whether events can be resized. RequiresInteractionplugin. Default:true. -
eventResizableFromStart(boolean): Allows resizing an event by dragging its start edge. RequiresInteractionplugin. Default:false. -
dragScroll(boolean): Auto-scrolls the calendar when the pointer nears the edge during a drag. RequiresInteractionplugin. Default:true. -
eventDragMinDistance(integer): Pixel distance the pointer must travel before a drag begins. RequiresInteractionplugin. Default:5. -
longPressDelay(integer): Milliseconds a touch must be held before drag or selection activates. Default:1000. -
eventLongPressDelay(integer): OverrideslongPressDelayfor event dragging on touch devices. -
selectable(boolean): Allows users to highlight date or time ranges by clicking and dragging. RequiresInteractionplugin. Default:false. -
selectMinDistance(integer): Pixel distance the pointer must travel before a selection begins. RequiresInteractionplugin. Default:5. -
selectLongPressDelay(integer): OverrideslongPressDelayfor date selection on touch devices. -
selectBackgroundColor(string): Background color of the active selection highlight. -
unselectAuto(boolean): Clears the selection when the user clicks outside it. RequiresInteractionplugin. Default:true. -
unselectCancel(string): CSS selector for elements that block automatic deselection. -
dragConstraint(function): Called on each pointer movement during a drag. Returnfalseto block the drop at the current position. -
resizeConstraint(function): Called on each pointer movement during a resize. Returnfalseto block the resize at the current size. -
selectConstraint(function): Called on each pointer movement during a selection. Returnfalseto block the selection at the current range.
Resources
-
resources(array | object | function): Resource data for resource views. Pass an array of plain objects, an object with aurlproperty for HTTP fetching, or a custom function. -
datesAboveResources(boolean): Renders date headings above resource headings in resource views. Default:false. -
filterEventsWithResources(boolean): Hides events that do not belong to the current resource list in non-resource views. Default:false. -
filterResourcesWithEvents(boolean): Hides resources with no events in the current date range from resource views. Default:false. -
refetchResourcesOnNavigate(boolean): Re-fetches resources each time the user navigates to a new date. Default:false. -
resourceLabelContent(string | object | function): Custom content inside each resource label element. -
resourceLabelDidMount(function): Fires after a resource label element is inserted into the DOM. -
resourceExpand(function): Fires when a nested resource group is expanded or collapsed inresourceTimelineviews.
Resource Object Reference
-
id(integer | string): Unique resource identifier. Coerced to a string internally. -
title(Content): Text displayed in the resource column or row header. -
eventBackgroundColor(string): Default background color for all events belonging to this resource. -
eventTextColor(string): Default text color for all events belonging to this resource. -
expanded(boolean): Controls whether a resource with nested children renders expanded or collapsed. Default:true. -
extendedProps(object): Custom properties passed through to the Resource object. -
children(array): Nested resource definitions for hierarchical grouping inresourceTimelineviews.
Formatting
-
dayHeaderFormat(object | function): Format of column heading text. Default varies by view. -
dayHeaderAriaLabelFormat(object | function): Format ofaria-labelattribute text in column headings. -
dayCellFormat(object | function): Format of day number text inside cells indayGridMonthview. Default:{day: 'numeric'}. -
titleFormat(object | function): Format of the header toolbar title text. Default varies by view. -
listDayFormat(object | function): Format of the left-side date heading in list views. Default:{weekday: 'long'}. -
listDaySideFormat(object | function): Format of the right-side date text in list views. Default:{year: 'numeric', month: 'long', day: 'numeric'}. -
monthHeaderFormat(object | function): Format of month headings inresourceTimelineYearview. -
allDayContent(Content | function): Content displayed in the all-day slot row heading. -
allDaySlot(boolean): Shows or hides the all-day slot row. Default:true. -
noEventsContent(Content | function): Content shown in list view when no events exist for the range. Default:'No events'. -
icons(object | function): Icon definitions for expand and collapse buttons in resource timeline views.
Callbacks
-
dateClick(function): Fires when the user clicks a date or time slot. RequiresInteractionplugin. -
datesSet(function): Fires whenever the calendar’s displayed date range changes through navigation or view switching. -
eventClick(function): Fires when the user clicks an event element. -
eventMouseEnter(function): Fires when the pointer enters an event element. -
eventMouseLeave(function): Fires when the pointer leaves an event element. -
eventDragStart(function): Fires at the start of an event drag. RequiresInteractionplugin. -
eventDragStop(function): Fires when an event drag ends, before position updates apply. RequiresInteractionplugin. -
eventDrop(function): Fires after an event is dropped at a new date, time, or resource. RequiresInteractionplugin. -
eventResizeStart(function): Fires at the start of an event resize. RequiresInteractionplugin. -
eventResizeStop(function): Fires when a resize ends, before duration updates apply. RequiresInteractionplugin. -
eventResize(function): Fires after an event’s duration changes through a completed resize. RequiresInteractionplugin. -
select(function): Fires when a date or time range selection completes. RequiresInteractionplugin. -
unselect(function): Fires when the current selection is cleared. RequiresInteractionplugin. -
noEventsClick(function): Fires when the user clicks the “No events” area in list view. -
viewDidMount(function): Fires after a view is added to the DOM. -
loading(function): Fires when event or resource fetching starts or stops, passing a booleanisLoadingargument.
9. API methods.
// Read the current value of any calendar option
let currentDate = ec.getOption('date');
let activeView = ec.getOption('view');
// Update any option at runtime — the calendar re-renders to reflect the new value
ec.setOption('view', 'dayGridMonth');
ec.setOption('slotDuration', '00:15:00');
ec.setOption('firstDay', 1);
// Add a new event to the calendar and get back the parsed Event object
let added = ec.addEvent({
id: 'task-77',
title: 'Product Demo',
start: '2026-04-15 13:00:00',
end: '2026-04-15 14:00:00',
backgroundColor: '#27ae60'
});
// Retrieve a single Event object by its id — returns null if not found
let ev = ec.getEventById('task-77');
// Retrieve all events currently held in the calendar's internal storage
let allEvents = ec.getEvents();
// Remove a single event by id
ec.removeEventById('task-77');
// Update a single event — the calendar matches by the event's id property
ec.updateEvent({
id: 'standup-1',
title: 'Team Standup (rescheduled)',
start: '2026-04-07 09:30:00',
end: '2026-04-07 10:00:00'
});
// Refetch events from all configured event sources
ec.refetchEvents();
// Refetch resources from a URL or custom function
ec.refetchResources();
// Move the displayed date forward by one period (day, week, month, etc.)
ec.next();
// Move the displayed date backward by one period
ec.prev();
// Return the current View object
// Properties: type, title, currentStart, currentEnd, activeStart, activeEnd
let view = ec.getView();
console.log(view.type, view.currentStart, view.activeEnd);
// Get calendar date/time data for specific screen coordinates
// Useful for finding which date was clicked inside a multi-day event
ec.setOption('eventClick', function(info) {
let point = ec.dateFromPoint(info.jsEvent.clientX, info.jsEvent.clientY);
if (point) {
// point.date is a Date object; point.allDay is a boolean; point.resource is the resource if applicable
console.log('Clicked on date:', point.date, '— allDay:', point.allDay);
}
});
// Programmatically clear the current selection
ec.unselect();10. Add the ec-dark class to any parent element of the calendar to activate Dark Mode. For automatic switching based on the operating system’s color scheme preference, use ec-auto-dark instead. The calendar reads the prefers-color-scheme media query and switches themes accordingly.
<body class="ec-dark"> <div id="team-schedule"></div> </body>
12. Override the default CSS variables to customize the themes.
.ec {
color-scheme: light;
/* Main colors */
--ec-color-400: oklch(70.8% 0 0);
--ec-color-300: oklch(87% 0 0);
--ec-color-200: oklch(92.2% 0 0);
--ec-color-100: oklch(97% 0 0);
--ec-color-50: oklch(98.5% 0 0);
/* General props */
--ec-bg-color: #fff;
--ec-text-color: currentcolor;
--ec-border-color: var(--ec-color-300);
/* Buttons */
--ec-button-bg-color: var(--ec-bg-color);
--ec-button-border-color: var(--ec-border-color);
--ec-button-text-color: var(--ec-text-color);
--ec-button-active-bg-color: var(--ec-color-200);
--ec-button-active-border-color: var(--ec-color-400);
--ec-button-active-text-color: var(--ec-button-text-color);
/* Days */
--ec-today-bg-color: oklch(98.7% 0.026 102.212);
--ec-highlight-color: oklch(98.4% 0.019 200.873);
/* Events */
--ec-event-bg-color: oklch(70.7% 0.165 254.624);
--ec-event-text-color: #fff;
--ec-bg-event-color: var(--ec-color-300);
--ec-bg-event-opacity: 0.3;
--ec-event-col-gap: .375rem;
/* Now Indicator */
--ec-now-indicator-color: oklch(63.7% 0.237 25.331);
/* Popup */
--ec-popup-bg-color: var(--ec-bg-color);
.ec-dark & {
color-scheme: dark;
--ec-color-400: oklch(43.9% 0 0);
--ec-color-300: oklch(37.1% 0 0);
--ec-color-200: oklch(26.9% 0 0);
--ec-color-100: oklch(20.5% 0 0);
--ec-color-50: oklch(14.5% 0 0);
--ec-bg-color: var(--ec-color-100);
--ec-today-bg-color: oklch(28.6% 0.066 53.813);
--ec-highlight-color: oklch(30.2% 0.056 229.695);
--ec-bg-event-opacity: 0.5;
}
@media (prefers-color-scheme: dark) {
.ec-auto-dark & {
color-scheme: dark;
--ec-color-400: oklch(43.9% 0 0);
--ec-color-300: oklch(37.1% 0 0);
--ec-color-200: oklch(26.9% 0 0);
--ec-color-100: oklch(20.5% 0 0);
--ec-color-50: oklch(14.5% 0 0);
--ec-bg-color: var(--ec-color-100);
--ec-today-bg-color: oklch(28.6% 0.066 53.813);
--ec-highlight-color: oklch(30.2% 0.056 229.695);
--ec-bg-event-opacity: 0.5;
}
}
}Alternatives:
- FullCalendar: A lightweight yet powerful and developer-friendly JavaScript library to create flexible, draggable event calendars on the modern web app.
- Toast UI Calendar: A full-featured calendar library used to showcase custom events, schedules, tasks in daily, weekly, and monthly views.
The post Full-Featured Drag-and-Drop JavaScript Event Calendar with Resource & Timeline Views appeared first on CSS Script.
Discover more from RSS Feeds Cloud
Subscribe to get the latest posts sent to your email.
