The FullCalendar Interaction Plugin provides interactive functionality for FullCalendar, enabling users to perform drag-and-drop operations, resize events, click on dates, and select date ranges. It serves as an essential plugin that extends the core FullCalendar functionality with comprehensive user interaction capabilities.
npm install @fullcalendar/interaction@fullcalendar/core ~6.1.19import interactionPlugin from '@fullcalendar/interaction';
import { Draggable, ThirdPartyDraggable } from '@fullcalendar/interaction';For CommonJS:
const interactionPlugin = require('@fullcalendar/interaction').default;
const { Draggable, ThirdPartyDraggable } = require('@fullcalendar/interaction');For global/IIFE builds:
<script src="path/to/fullcalendar/interaction/index.global.js"></script>
<script>
const interactionPlugin = FullCalendar.Interaction.default;
const { Draggable, ThirdPartyDraggable } = FullCalendar.Interaction;
</script>import { Calendar } from '@fullcalendar/core';
import interactionPlugin from '@fullcalendar/interaction';
import dayGridPlugin from '@fullcalendar/daygrid';
const calendarEl = document.getElementById('calendar');
const calendar = new Calendar(calendarEl, {
plugins: [interactionPlugin, dayGridPlugin],
initialView: 'dayGridMonth',
// Enable interaction features
editable: true, // Enables event dragging and resizing
selectable: true, // Enables date selection
// Event handlers for interactions
dateClick: (info) => {
console.log('Date clicked:', info.dateStr);
},
eventDrop: (info) => {
console.log('Event dropped:', info.event.title);
},
eventResize: (info) => {
console.log('Event resized:', info.event.title);
},
select: (info) => {
console.log('Date range selected:', info.startStr, 'to', info.endStr);
},
events: [
{ title: 'Meeting', start: '2023-05-15', editable: true },
{ title: 'Conference', start: '2023-05-20', end: '2023-05-22' }
]
});
calendar.render();The interaction plugin is built around several key components:
Core plugin functionality that registers all interaction capabilities with FullCalendar. This is the primary export that enables interactive features.
declare const interactionPlugin: PluginDef;
export default interactionPlugin;The plugin automatically registers:
Functionality for making external DOM elements draggable onto calendars, with built-in drag feedback and event creation.
export class Draggable {
constructor(el: HTMLElement, settings?: ExternalDraggableSettings);
destroy(): void;
}
interface ExternalDraggableSettings {
eventData?: DragMetaGenerator;
itemSelector?: string;
minDistance?: number;
longPressDelay?: number;
appendTo?: HTMLElement;
}
type DragMetaGenerator = DragMetaInput | ((el: HTMLElement) => DragMetaInput);Bridge functionality for integrating existing third-party drag-and-drop libraries with FullCalendar.
export class ThirdPartyDraggable {
constructor(
containerOrSettings?: EventTarget | ThirdPartyDraggableSettings,
settings?: ThirdPartyDraggableSettings
);
destroy(): void;
}
interface ThirdPartyDraggableSettings {
eventData?: DragMetaGenerator;
itemSelector?: string;
mirrorSelector?: string;
}Comprehensive type definitions for all interaction event arguments, providing detailed information about user interactions.
export interface DateClickArg extends DatePointApi {
dayEl: HTMLElement;
jsEvent: MouseEvent;
view: ViewApi;
}
export interface EventDragStartArg {
el: HTMLElement;
event: EventApi;
jsEvent: MouseEvent;
view: ViewApi;
}
export interface EventResizeDoneArg extends EventChangeArg {
el: HTMLElement;
startDelta: Duration;
endDelta: Duration;
jsEvent: MouseEvent;
view: ViewApi;
}
export interface DropArg extends DatePointApi {
draggedEl: HTMLElement;
jsEvent: MouseEvent;
view: ViewApi;
}interface DatePointApi {
date: Date;
dateStr: string;
allDay: boolean;
}
interface EventChangeArg {
oldEvent: EventApi;
event: EventApi;
relatedEvents: EventApi[];
revert: () => void;
}
type DurationInput = DurationObjectInput | string | number;
interface DurationObjectInput {
years?: number;
months?: number;
days?: number;
hours?: number;
minutes?: number;
seconds?: number;
milliseconds?: number;
}
type DateInput = Date | string | number;The plugin adds the following option to FullCalendar:
interface CalendarOptions {
fixedMirrorParent?: HTMLElement;
}Custom Drag Mirror Positioning:
const calendar = new Calendar(calendarEl, {
plugins: [interactionPlugin],
// Constrain drag mirrors to a specific container
fixedMirrorParent: document.getElementById('drag-container'),
// Enable drag scrolling during long drags
dragScroll: true,
// Customize drag behavior
eventDragMinDistance: 5, // Minimum pixels before drag starts
longPressDelay: 1000, // Touch delay in milliseconds
dragRevertDuration: 300, // Animation duration for failed drags
// Validation and constraints
eventConstraint: 'businessHours', // Constrain events to business hours
selectConstraint: 'businessHours', // Constrain selections to business hours
// Advanced interaction callbacks
eventDragStart: (info) => {
console.log('Drag started:', info.event.title);
// Add visual feedback
document.body.classList.add('dragging-active');
},
eventDragStop: (info) => {
console.log('Drag ended:', info.event.title);
// Remove visual feedback
document.body.classList.remove('dragging-active');
},
// Custom drop validation
dropAccept: (draggableEl) => {
// Only accept elements with specific classes
return draggableEl.classList.contains('approved-draggable');
},
// Handle cross-calendar events
eventReceive: (info) => {
console.log('Event received from external source:', info.event.title);
// Validate and potentially modify the received event
if (!info.event.title) {
info.revert(); // Reject events without titles
}
}
});Touch-Optimized Configuration:
const mobileCalendar = new Calendar(calendarEl, {
plugins: [interactionPlugin],
// Touch-friendly settings
eventLongPressDelay: 500, // Shorter press delay for mobile
eventDragMinDistance: 8, // Slightly larger min distance for touch
dragScroll: true, // Enable auto-scroll during drag
// Optimized for touch interactions
selectLongPressDelay: 800, // Date selection long press
unselectAuto: false, // Don't auto-unselect on outside click
eventDragStart: (info) => {
// Add touch-specific visual feedback
info.el.classList.add('touch-dragging');
},
eventDragStop: (info) => {
info.el.classList.remove('touch-dragging');
}
});