Livewire Drag And Drop - v2.0.1
API Reference - Livewire Drag and Drop
Complete reference for ArtisanPack UI Livewire Drag and Drop directives, events, and methods.
Module Exports
Default Export
The package exports a default function for manual plugin registration with Alpine.js.
Syntax
import LivewireDragAndDrop from '@artisanpack-ui/livewire-drag-and-drop'
document.addEventListener('alpine:init', () => {
LivewireDragAndDrop(Alpine)
})
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
Alpine |
object |
Yes | The Alpine.js instance to register directives with |
Named Exports
For advanced usage, the package also exports individual functions:
registerDirectives(Alpine)
Registers the drag-and-drop directives (x-drag-context, x-drag-item) with Alpine.js.
import { registerDirectives } from '@artisanpack-ui/livewire-drag-and-drop'
document.addEventListener('alpine:init', () => {
registerDirectives(Alpine)
})
registerLivewireHooks(Livewire)
Registers Livewire lifecycle hooks for proper DOM morphing support.
import { registerLivewireHooks } from '@artisanpack-ui/livewire-drag-and-drop'
document.addEventListener('livewire:init', () => {
registerLivewireHooks(Livewire)
})
Note: When using the default export LivewireDragAndDrop(Alpine), it automatically calls both registerDirectives and registerLivewireHooks (if Livewire is available). The named exports are provided for advanced scenarios where granular control is needed.
Side-Effect Import
For automatic registration, you can use a side-effect import:
import '@artisanpack-ui/livewire-drag-and-drop'
This automatically registers the directives when Alpine.js initializes and Livewire hooks when Livewire initializes.
Alpine.js Directives
x-drag-context
Creates a drag-and-drop context container that manages draggable items and handles drop operations.
Syntax
<div x-drag-context="expression" [additional-attributes]>
<!-- draggable items -->
</div>
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
expression |
string |
Yes | JavaScript expression to handle drop events |
Event Handler Signature
The expression receives an event object with the following detail structure:
{
orderedIds: [] // Array of item IDs in their new order
}
Attributes Added
The directive automatically adds the following attributes to the container:
role="application"- Identifies as an interactive applicationaria-label="Drag and drop interface"- Provides accessible description
Created Elements
- Live Region: A hidden
divwitharia-live="polite"for screen reader announcements - Instructions: Global drag instructions element (if not already present)
Example Usage
<div
x-data="{
handleReorder(event) {
const { oldIndex, newIndex } = event.detail;
$wire.reorderItems(oldIndex, newIndex);
}
}"
x-drag-context="handleReorder($event.detail)"
@drag:end="handleReorder($event)"
class="drag-container"
>
<!-- draggable items -->
</div>
Event Listeners
The context container listens for these events:
dragover- Prevents default and sets drop effectdrop- Handles item dropping and calculates new positionkeydown- Handles Escape key for canceling operations
x-drag-item
Designates an element as draggable within a drag context.
Syntax
<div x-drag-item="data" [additional-attributes]>
Item content
</div>
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
data |
`object | string` | Yes |
Data Object Structure
The data parameter can be any serializable object. Common structure:
interface DragItemData {
id: number|string; // Unique identifier
[key: string]: any; // Additional properties
}
Attributes Added
The directive automatically adds these attributes:
draggable="true"- Enables HTML5 drag and droptabindex="0"- Makes item keyboard focusablerole="button"- Identifies as an interactive buttonaria-grabbed="false"- Indicates grab state for screen readersaria-describedby="drag-instructions"- Links to instruction text
Example Usage
<div x-drag-item="{{ json_encode(['id' => 1, 'title' => 'Task 1']) }}" class="drag-item">
<span>Task 1</span>
</div>
State Classes
The following CSS classes are automatically added/removed:
.is-grabbing- Added during drag operations- Applied inline styles:
opacity: 0.5- During dragoutline: 2px solid #007cba- On focus
Keyboard Navigation
| Key | Action |
|---|---|
Space or Enter |
Grab/release item |
ArrowUp or ArrowLeft |
Move item up/left |
ArrowDown or ArrowRight |
Move item down/right |
Escape |
Cancel drag operation |
Tab |
Navigate between items |
Event Listeners
Each draggable item listens for:
dragstart- Initiates drag operationdragend- Completes drag operationkeydown- Handles keyboard navigationfocus- Adds focus stylingblur- Removes focus styling
Events
drag:end
Fired when a drag operation completes successfully, either via mouse/touch or keyboard.
Event Detail
interface DragEndEvent extends CustomEvent {
detail: {
group: string; // Context group identifier
oldIndex: number; // Original item position
newIndex: number; // New item position
sourceElement: Element; // The dragged element
targetElement: Element; // Drop target element
};
bubbles: true; // Event bubbles up the DOM
}
Usage Examples
Basic Event Handling:
document.addEventListener('drag:end', (event) => {
const { oldIndex, newIndex } = event.detail;
console.log(`Item moved from ${oldIndex} to ${newIndex}`);
});
Livewire Integration:
<div
x-data="{
handleDragEnd(event) {
const { orderedIds } = event.detail;
$wire.reorderItems(orderedIds);
}
}"
@drag:end="handleDragEnd($event)"
>
<!-- Draggable items -->
</div>
Multiple Context Handling:
document.addEventListener('drag:end', (event) => {
const { group, oldIndex, newIndex } = event.detail;
switch (group) {
case 'todos':
updateTodos(oldIndex, newIndex);
break;
case 'kanban-todo':
moveKanbanCard('todo', oldIndex, newIndex);
break;
}
});
JavaScript API
LivewireDragAndDrop()
Main initialization function that registers Alpine.js directives.
Syntax
LivewireDragAndDrop(Alpine)
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
Alpine |
object |
Yes | Alpine.js instance |
Example
import Alpine from 'alpinejs'
import LivewireDragAndDrop from '@artisanpack-ui/livewire-drag-and-drop'
document.addEventListener('alpine:init', () => {
LivewireDragAndDrop(Alpine)
})
Alpine.start()
Accessibility Features
ARIA Attributes
The package automatically manages these ARIA attributes:
Container Attributes
role="application"- Indicates interactive applicationaria-label="Drag and drop interface"- Describes the interface
Item Attributes
role="button"- Identifies items as interactive buttonsaria-grabbed="false|true"- Indicates grab statearia-pressed="false|true"- Indicates activation statearia-describedby="drag-instructions"- Links to instructions
Live Region
aria-live="polite"- Announces changes to screen readersaria-atomic="true"- Reads entire region on changes
Screen Reader Announcements
The package provides automatic announcements for:
- Drag Start: "Item grabbed for dragging"
- Drag End: "Item released"
- Keyboard Movement: "Moved to position X of Y"
- Cancel: "Drag operation cancelled"
Focus Management
- Items receive proper focus indicators
- Focus remains on moved items after keyboard operations
- Tab order is maintained during drag operations
CSS Classes
Required Classes
These classes must be defined in your CSS:
.sr-only {
position: absolute !important;
width: 1px !important;
height: 1px !important;
padding: 0 !important;
margin: -1px !important;
overflow: hidden !important;
clip: rect(0, 0, 0, 0) !important;
white-space: nowrap !important;
border: 0 !important;
}
Auto-Applied Classes
The package automatically applies these classes:
.is-grabbing
Applied to items during drag operations. Recommended styles:
.is-grabbing {
opacity: 0.7;
transform: scale(1.02);
z-index: 1000;
cursor: grabbing;
}
Recommended Styles
Focus Indicators
[x-drag-item]:focus {
outline: 2px solid #3b82f6;
outline-offset: 2px;
}
Drag Handles
.drag-handle {
cursor: grab;
color: #6b7280;
}
.drag-handle:hover {
color: #374151;
}
Container Styles
[x-drag-context] {
position: relative;
}
[x-drag-context]:focus-within {
/* Highlight active container */
}
Advanced Usage
Custom Group Identifiers
Use the group attribute to handle multiple drag contexts:
<div x-drag-context="handleDrop" data-group="todos">
<!-- todo items -->
</div>
<div x-drag-context="handleDrop" data-group="in-progress">
<!-- in-progress items -->
</div>
Cross-Container Dragging
Enable dragging between different containers:
<!-- Source Container -->
<div
x-drag-context="handleSourceDrop"
@dragover.prevent
class="source-container"
>
<div x-drag-item="{ id: 1, type: 'task' }">Task 1</div>
</div>
<!-- Target Container -->
<div
x-drag-context="handleTargetDrop"
@dragover.prevent
@drop="handleCrossContainerDrop($event)"
class="target-container"
>
<!-- Drop zone -->
</div>
Custom Data Transfer
Access the HTML5 DataTransfer API for advanced use cases:
<div
x-drag-item="{ id: 1, title: 'Task 1' }"
@dragstart="$event.dataTransfer.setData('text/html', $el.outerHTML)"
@dragstart="$event.dataTransfer.setDragImage(customImage, 0, 0)"
>
Task content
</div>
Performance Optimization
For large lists, consider using intersection observers:
<div x-data="{ visible: false }" x-intersect="visible = true">
<template x-if="visible">
<div x-drag-context="handleDrop">
<!-- Heavy content -->
</div>
</template>
</div>
Browser Compatibility
Required Features
- Drag and Drop API: IE 11+, all modern browsers
- Custom Events: IE 9+, all modern browsers
- ARIA Attributes: All browsers with screen reader support
- Alpine.js: As per Alpine.js requirements
Feature Detection
// Check for drag and drop support
if ('draggable' in document.createElement('div')) {
// Drag and drop is supported
LivewireDragAndDrop(Alpine)
} else {
// Provide fallback UI
console.warn('Drag and drop not supported')
}
Progressive Enhancement
The package gracefully degrades when JavaScript is disabled:
- Items remain focusable and interactive
- Form elements continue to work normally
- Content remains accessible to screen readers
Error Handling
Common Errors
Directive Registration Errors:
// Ensure Alpine is available before registration
if (typeof Alpine !== 'undefined') {
LivewireDragAndDrop(Alpine)
} else {
console.error('Alpine.js not found')
}
Context Validation:
// x-drag-item validates its context
if (!dragContext || !dragContext._dragContext) {
console.warn('x-drag-item must be used within x-drag-context')
return
}
Debug Mode
Enable detailed logging:
// Add to your Alpine.js setup
Alpine.store('debug', true)
document.addEventListener('drag:end', (event) => {
if (Alpine.store('debug')) {
console.log('Drag operation details:', event.detail)
}
})
Migration Guide
From Version 0.x to 1.x
Breaking Changes:
- Event Structure:
drag:endnow includessourceElementandtargetElement - CSS Classes:
.draggingrenamed to.is-grabbing - ARIA Attributes: Enhanced accessibility attributes
Update Steps:
<!-- Old (0.x) -->
<div @drag:end="handleDrop($event.detail.oldIndex, $event.detail.newIndex)">
<!-- New (2.x) -->
<div @drag:end="handleDrop($event.detail.orderedIds)">
/* Old (0.x) */
.dragging { opacity: 0.5; }
/* New (1.x) */
.is-grabbing { opacity: 0.7; transform: scale(1.02); }
Related Documentation:
- Getting Started Guide - Installation and basic usage
- Accessibility Guide - Detailed accessibility information
- Examples - Advanced implementation patterns