events
Listen to drag start, drag, and drag end events
The events
plugin provides callbacks that fire during different phases of dragging. Get notified when dragging starts, during movement, and when it ends - perfect for updating UI state, logging, or triggering animations.
events({
onDragStart: (data) => console.log('Started dragging'),
onDrag: (data) => console.log('Moving:', data.offset),
onDragEnd: (data) => console.log('Finished dragging'),
});
Basic Usage
import { events, Draggable } from '@neodrag/vanilla';
const element = document.getElementById('element');
const statusEl = document.getElementById('status');
const positionEl = document.getElementById('position');
new Draggable(element, [
events({
onDragStart: () => {
statusEl.textContent = 'dragging';
},
onDrag: (data) => {
positionEl.textContent = `${data.offset.x}, ${data.offset.y}`;
},
onDragEnd: () => {
statusEl.textContent = 'idle';
},
}),
]);
Event Data
All event callbacks receive a DragEventData
object with:
offset
- Current position{ x: number, y: number }
rootNode
- Element with draggable appliedcurrentNode
- Element being dragged (can change mid-drag)event
- The pointer event that triggered this callback
import { events, Draggable } from '@neodrag/vanilla';
const element = document.getElementById('element');
function logEventData(data) {
console.log('Position:', data.offset);
console.log('Root element:', data.rootNode);
console.log('Current element:', data.currentNode);
console.log('Pointer event:', data.event);
}
new Draggable(element, [
events({
onDragStart: logEventData,
onDrag: logEventData,
onDragEnd: logEventData,
}),
]);
Real-World Examples
Position Tracking with Velocity
import { events, Draggable } from '@neodrag/vanilla';
const element = document.getElementById('tracker');
const positionEl = document.getElementById('position');
const velocityEl = document.getElementById('velocity');
let lastTime = 0;
let lastPosition = { x: 0, y: 0 };
new Draggable(element, [
events({
onDrag: (data) => {
const now = Date.now();
const deltaTime = now - lastTime;
let velocityX = 0,
velocityY = 0;
if (deltaTime > 0) {
velocityX = Math.round(
((data.offset.x - lastPosition.x) / deltaTime) * 1000,
);
velocityY = Math.round(
((data.offset.y - lastPosition.y) / deltaTime) * 1000,
);
}
positionEl.textContent = `(${data.offset.x}, ${data.offset.y})`;
velocityEl.textContent = `(${velocityX}px/s, ${velocityY}px/s)`;
lastPosition = { ...data.offset };
lastTime = now;
},
}),
]);
Save Position to Storage
import { events, Draggable } from '@neodrag/vanilla';
const element = document.getElementById('element');
new Draggable(element, [
events({
onDragEnd: (data) => {
localStorage.setItem(
'elementPosition',
JSON.stringify({
x: data.offset.x,
y: data.offset.y,
timestamp: Date.now(),
}),
);
console.log('Position saved!');
},
}),
]);
Analytics Tracking
// Track user interactions for analytics
events({
onDragStart: (data) => {
analytics.track('drag_started', {
element: data.rootNode.id,
timestamp: Date.now(),
});
},
onDragEnd: (data) => {
analytics.track('drag_completed', {
element: data.rootNode.id,
finalPosition: data.offset,
timestamp: Date.now(),
});
},
});
Progress Indicator
// Show progress based on how far element has moved
const maxDistance = 300;
events({
onDragStart: () => {
progressBar.style.display = 'block';
},
onDrag: (data) => {
const distance = Math.sqrt(
data.offset.x ** 2 + data.offset.y ** 2,
);
const progress = Math.min((distance / maxDistance) * 100, 100);
progressBar.style.width = `${progress}%`;
},
onDragEnd: () => {
progressBar.style.display = 'none';
},
});
How It Works
The events plugin:
- Stores event data in its state during each hook
- Schedules callbacks using
ctx.effect.immediate()
for fast execution - Provides consistent data across all three event types
- Non-cancelable - Always runs regardless of other plugin cancellations
The callbacks fire in this order:
onDragStart
→onDrag
(repeatedly) →onDragEnd
API Reference
function events(options?: {
onDragStart?: (data: DragEventData) => void;
onDrag?: (data: DragEventData) => void;
onDragEnd?: (data: DragEventData) => void;
}): Plugin;
Options:
onDragStart
- Called when dragging beginsonDrag
- Called repeatedly during draggingonDragEnd
- Called when dragging ends
DragEventData:
offset
- Current position{ x: number, y: number }
rootNode
- Element with draggable appliedcurrentNode
- Element being draggedevent
- The pointer event that triggered this callback
Returns: A plugin object for use with draggable.