How to Implement Pragmatic Drag and Drop in Your React Application
A comprehensive guide to building performant, accessible drag-and-drop interfaces with Atlassian's Pragmatic Drag and Drop library
Drag-and-drop functionality has become essential for modern web applications, enabling users to reorganize content, manage tasks, and interact with interfaces in intuitive ways. Atlassian's Pragmatic Drag and Drop library offers a powerful, performant solution for implementing these interactions in React applications.
Unlike traditional drag-and-drop solutions that often bundle unnecessary features or impact performance, Pragmatic Drag and Drop takes a minimal, composable approach. Built on top of the browser's native Drag and Drop API, it provides just enough functionality to create robust drag-and-drop experiences without the overhead of larger libraries. Our web development services team regularly implements these patterns in client projects to create intuitive user experiences.
This guide covers everything you need to know to implement drag-and-drop in your React projects, from basic setup to advanced optimization techniques.
Why Atlassian's library stands out from alternatives
Performance-First Design
Minimal re-renders and efficient event handling keep your interfaces responsive even with complex drag operations.
Browser Native Foundation
Built directly on the native Drag and Drop API for reduced abstraction overhead and better browser compatibility.
Modular Architecture
Import only the functionality you need with focused packages that keep bundle sizes minimal.
React Hooks API
Clean, declarative hooks integrate naturally with modern React patterns and component architecture.
Installation and Initial Setup
Getting started with Pragmatic Drag and Drop requires installing the appropriate packages for your React application. The library is organized into focused packages that address different aspects of drag-and-drop functionality.
Installing Dependencies
For most React applications, you'll want at minimum the core and React packages:
npm install @atlaskit/pragmatic-drag-and-drop @atlaskit/pragmatic-drag-and-drop-react
Or with yarn:
yarn add @atlaskit/pragmatic-drag-and-drop @atlaskit/pragmatic-drag-and-drop-react
The core package provides the fundamental drag-and-drop functionality, while the React package includes hooks and components specifically designed for React applications.
Provider Configuration
Many Pragmatic Drag and Drop features require wrapping your application or relevant component tree with a provider component. This provider manages shared state and coordinates drag-and-drop operations across your application. For basic implementations, the provider setup may be minimal or optional depending on which features you use. Advanced scenarios, particularly those involving complex drag sources and drop targets, benefit from proper provider configuration.
The modular package structure means applications only include the code they actually use, keeping your bundles lean and your performance optimal.
Creating Draggable Elements
Making elements draggable is the foundation of any drag-and-drop interface. Pragmatic Drag and Drop provides clean APIs for defining draggable items while maintaining flexibility for different use cases.
Using the useDraggable Hook
The primary way to make an element draggable in React applications is through the useDraggable hook. This hook connects your component to the drag-and-drop system while keeping your component logic clean and testable.
import { useDraggable } from '@atlaskit/pragmatic-drag-and-drop-react';
function DraggableItem({ id, children }) {
const { draggableProps, setDraggableRef } = useDraggable({
draggableId: id,
});
return (
<div ref={setDraggableRef} {...draggableProps}>
{children}
</div>
);
}
The useDraggable hook returns draggableProps that should be spread onto the draggable element, along with a ref function that connects the element to the drag-and-drop system. The draggableId parameter uniquely identifies this draggable item within your application.
Configuring Drag Behavior
The hook accepts additional options to customize drag behavior:
- dragHandle: Restrict dragging to only when the user clicks a specific handle element within the draggable
- getInitialData: Provide custom data to be associated with the drag event
- mode: Specify whether the draggable can be moved within a list or used for other purposes
These options allow fine-grained control over how users interact with draggable elements, supporting use cases from simple sortable lists to complex interfaces with constrained movement.
Creating Drop Targets
Drop targets receive dragged items and define where they can be placed. Pragmatic Drag and Drop provides mechanisms for defining drop zones with clear feedback during drag operations.
Using the useDropTarget Hook
Similar to the draggable hook, useDropTarget connects elements to the drag-and-drop system as potential drop destinations:
import { useDropTarget } from '@atlaskit/pragmatic-drag-and-drop-react';
function DropZone({ onDrop, children }) {
const { dropTargetProps, setDropTargetRef, isOverCurrent } = useDropTarget({
dropTargetId: 'drop-zone',
});
return (
<div
ref={setDropTargetRef}
{...dropTargetProps}
className={isOverCurrent ? 'highlight' : ''}
>
{children}
</div>
);
}
The isOverCurrent indicator provides a simple way to show visual feedback when a dragged item is over the drop target. This feedback helps users understand where items can be dropped.
Handling Drop Events
When an item is dropped on a target, your application needs to respond appropriately. This typically involves updating application state to reflect the new arrangement:
const { dropTargetProps, setDropTargetRef, isOverCurrent } = useDropTarget({
dropTargetId: 'reorder-list',
});
const handleDragEnd = (event) => {
if (event.source.droppableId && event.destination) {
// Update your state to reflect the drop
moveItem(event.source.index, event.destination.index);
}
};
The drag end event provides information about the source and destination of the drag operation, enabling precise state updates.
Implementing Sortable Lists
Sortable lists represent one of the most common use cases for drag-and-drop functionality. Pragmatic Drag and Drop provides patterns specifically designed for reordering items in lists and grids.
Combining Draggable and Drop Target
For sortable lists, each item typically needs both draggable and drop target functionality. This allows items to be reordered relative to other items in the list:
import {
useDraggable,
useDropTarget,
combine
} from '@atlaskit/pragmatic-drag-and-drop-react';
function SortableItem({ id, index }) {
const draggable = useDraggable({ draggableId: id });
const dropTarget = useDropTarget({ dropTargetId: id });
return (
<div
ref={combine(draggable.setDraggableRef, dropTarget.setDropTargetRef)}
{...combine(draggable.draggableProps, dropTarget.dropTargetProps)}
>
Item {index}
</div>
);
}
The combine function allows a single element to serve as both a draggable item and a drop target, enabling items to be reordered by dragging them between positions in the list.
Reordering Logic
When items are dropped, the application needs to calculate the new order. This typically involves removing the item from its original position and inserting it at the new position:
function reorderList(items, sourceIndex, destinationIndex) {
const result = [...items];
const [removed] = result.splice(sourceIndex, 1);
result.splice(destinationIndex, 0, removed);
return result;
}
This pattern works for single lists and can be extended to handle nested lists, kanban-style boards, and other more complex organizational structures.
Common Implementation Patterns
Certain drag-and-drop patterns appear frequently across different types of applications. Understanding these patterns helps developers implement common use cases efficiently.
Kanban Boards
Kanban boards with columns and cards represent a natural fit for drag-and-drop functionality. Each column acts as a drop target, and cards are draggable between columns. This pattern is particularly useful for project management applications, task tracking systems, and workflow visualization tools. When building complex AI-powered applications, drag-and-drop interfaces can help users intuitively manage AI workflows and automation pipelines.
Tree Structures
Hierarchical tree structures like file browsers or organizational charts require drag-and-drop that respects parent-child relationships. Implementing these structures involves tracking drop targets at multiple levels, with nested drop targets and validation rules to prevent invalid nesting.
Grid Reordering
Grid-based layouts like image galleries or widget dashboards require two-dimensional drag-and-drop. The implementation is similar to lists but with additional logic for horizontal and vertical positioning, cell sizing, and snap-to-grid behavior.
These patterns demonstrate the flexibility of Pragmatic Drag and Drop for building a wide range of interactive interfaces while maintaining consistent performance characteristics.
Performance Optimization Techniques
Drag-and-drop operations can impact application performance if not implemented carefully. Pragmatic Drag and Drop includes several mechanisms for maintaining smooth interactions even with complex interfaces.
Minimizing Re-renders
React applications can experience performance issues when drag operations trigger unnecessary component re-renders. Several strategies help maintain performance:
- Memoization: Wrap draggable items with
React.memoto prevent re-rendering when parent state changes but the item itself hasn't changed - Selective state updates: Update only the specific portions of state that change during drag operations rather than triggering broad state updates
- Stable references: Ensure draggable IDs and item references remain stable across renders
import { memo } from 'react';
const SortableItem = memo(function SortableItem({ id, children }) {
const draggable = useDraggable({ draggableId: id });
// ... component implementation
});
Combining these techniques with proper state management using TypeScript and Redux Toolkit helps maintain application performance at scale.
Efficient Event Handling
During drag operations, the browser fires numerous events. Pragmatic Drag and Drop is designed to handle these efficiently, but there are additional steps developers can take:
- Avoid expensive operations in event handlers: Defer complex calculations until drag operations complete
- Use CSS transforms for visual feedback: Leverage hardware-accelerated CSS properties rather than updating layout with JavaScript
- Debounce state updates: For continuous updates like position tracking, consider debouncing to reduce update frequency
Large List Considerations
When dealing with large numbers of draggable items, additional optimizations become important:
- Virtualization: For very long lists, combine drag-and-drop with windowing libraries that only render visible items
- Pagination: Consider whether all items need to be draggable simultaneously, or whether pagination could reduce the number of active draggable elements
- Lazy loading: Load draggable items as needed rather than rendering everything upfront
These optimization techniques ensure your drag-and-drop interfaces remain responsive even as your application scales.
Testing Drag-and-Drop Implementations
Automated testing of drag-and-drop functionality presents unique challenges, as these interactions rely heavily on browser events and DOM manipulation. Pragmatic Drag and Drop is designed with testability in mind.
Unit Testing Individual Components
Testing individual draggable or drop target components involves simulating drag events and verifying component behavior:
import { render, fireEvent } from '@testing-library/react';
test('draggable item responds to drag start', () => {
const handleDragStart = jest.fn();
const { getByText } = render(
<DraggableItem id="test-id" onDragStart={handleDragStart}>
Test Item
</DraggableItem>
);
const item = getByText('Test Item');
fireEvent.dragStart(item);
expect(handleDragStart).toHaveBeenCalled();
});
Integration Testing Complete Flows
End-to-end tests verify that drag-and-drop works correctly from the user's perspective. These tests simulate complete drag operations including drag start, drag over, and drop events.
Testing Considerations
When testing drag-and-drop functionality, keep these points in mind:
- Browser differences: Drag-and-drop behavior can vary between browsers; test in multiple environments
- Event sequences: Ensure tests simulate the complete expected event sequence
- State consistency: Verify that component state remains consistent after drag operations
- Error handling: Test how your application handles invalid drop operations
Proper testing ensures your drag-and-drop implementations work reliably across different scenarios and browsers.
Common Questions About Pragmatic Drag and Drop
React Component Architecture
Learn best practices for structuring React components and managing state in complex applications.
Learn moreBuilding Vue.js Grid Layouts
Explore alternative approaches to implementing grid layouts with Vue.js for comparison.
Learn moreHeadless UI Alternatives
Compare Pragmatic Drag and Drop with other headless UI libraries for React.
Learn moreSources
- Atlassian Design System - Pragmatic Drag and Drop - Official documentation and component APIs
- GitHub - pragmatic-drag-and-drop - Repository documentation and examples
- LogRocket Blog - Implement Pragmatic Drag Drop Library Guide - Comprehensive tutorial and implementation guide