Interactive functionality for FullCalendar including event dragging, resizing, date clicking, and external drag-and-drop support
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
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');
}
});