@dnd-kit vs react-beautiful-dnd vs Pragmatic DnD: Drag & Drop in 2026
TL;DR
react-beautiful-dnd is deprecated — Atlassian moved on and so should you. In 2026, @dnd-kit is the default choice for most React drag-and-drop needs: it's small, accessible, framework-agnostic, and actively maintained. Atlassian's Pragmatic drag-and-drop is the better pick if you need production-grade performance at Jira/Trello scale with zero abstraction overhead.
Key Takeaways
- react-beautiful-dnd: ~1.2M weekly downloads but no longer maintained by Atlassian — deprecated
- @dnd-kit: ~2.8M weekly downloads — the community standard, 6KB core, excellent accessibility
- @atlaskit/pragmatic-drag-and-drop: Atlassian's replacement — tiny (< 4KB), no animation opinions, built for performance
- @dnd-kit wins for most projects: rich plugin system, sortable preset, collision detection strategies
- Pragmatic DnD wins for custom, performance-critical implementations (Jira, Confluence, Trello)
- Both are TypeScript-native and production-proven at scale
Download Trends
| Package | Weekly Downloads | Status | Bundle Size |
|---|---|---|---|
react-beautiful-dnd | ~1.2M | ⚠️ Deprecated | ~30KB |
@dnd-kit/core | ~2.8M | ✅ Active | ~6KB |
@atlaskit/pragmatic-drag-and-drop | ~180K | ✅ Active | ~3.5KB |
Legacy downloads of react-beautiful-dnd reflect existing projects, not new installs.
The Full Story
react-beautiful-dnd: The Departed Standard
react-beautiful-dnd was the gold standard for drag-and-drop in React from 2018–2022. Atlassian built it for Trello and open-sourced it. The animations were smooth, the API was ergonomic, and it handled keyboard accessibility better than anything else at the time.
In 2022, Atlassian announced they were no longer maintaining it:
"We no longer recommend react-beautiful-dnd for new projects. We have moved to @atlaskit/pragmatic-drag-and-drop." — Atlassian, 2022
The library still works, but:
- No security updates
- No new features
- No React 19 compatibility guaranteed
- Issues and PRs are ignored
The ~1.2M weekly downloads are legacy projects that haven't migrated yet. Don't use it for new projects.
@dnd-kit: The Community Standard
@dnd-kit by Claudéric Demers is what react-beautiful-dnd should have evolved into. Built from scratch with modern React in mind:
import {
DndContext,
closestCenter,
KeyboardSensor,
PointerSensor,
useSensor,
useSensors,
} from "@dnd-kit/core"
import {
SortableContext,
sortableKeyboardCoordinates,
verticalListSortingStrategy,
useSortable,
} from "@dnd-kit/sortable"
import { CSS } from "@dnd-kit/utilities"
function SortableItem({ id }: { id: string }) {
const { attributes, listeners, setNodeRef, transform, transition } =
useSortable({ id })
const style = {
transform: CSS.Transform.toString(transform),
transition,
}
return (
<div ref={setNodeRef} style={style} {...attributes} {...listeners}>
{id}
</div>
)
}
function SortableList({ items }: { items: string[] }) {
const sensors = useSensors(
useSensor(PointerSensor),
useSensor(KeyboardSensor, {
coordinateGetter: sortableKeyboardCoordinates,
})
)
return (
<DndContext sensors={sensors} collisionDetection={closestCenter}>
<SortableContext items={items} strategy={verticalListSortingStrategy}>
{items.map((id) => (
<SortableItem key={id} id={id} />
))}
</SortableContext>
</DndContext>
)
}
What makes @dnd-kit excellent:
- Modular architecture: Core is 6KB. Install only what you need (@dnd-kit/sortable, @dnd-kit/modifiers, @dnd-kit/utilities)
- Headless: Zero opinion on styling or animations — you control the UI
- Collision detection strategies: closestCenter, closestCorners, rectIntersection, pointerWithin — or write your own
- Multiple containers: Drag between lists, grids, trees out of the box
- Accessibility first: Screen reader announcements, keyboard navigation, ARIA attributes all handled
- Sensors: Pointer (mouse/touch), keyboard, and custom sensors supported
- Performance: Uses transform/translate only — no layout thrashing
Pragmatic drag-and-drop: Atlassian's New Approach
After shipping react-beautiful-dnd, Atlassian went back to basics when rebuilding Jira and Confluence. The result was @atlaskit/pragmatic-drag-and-drop — a library that makes zero assumptions:
import { draggable, dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter"
import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine"
import { useEffect, useRef } from "react"
function DraggableCard({ id, label }: { id: string; label: string }) {
const ref = useRef<HTMLDivElement>(null)
useEffect(() => {
const el = ref.current
if (!el) return
return combine(
draggable({
element: el,
getInitialData: () => ({ id }),
}),
dropTargetForElements({
element: el,
onDrop: ({ source }) => {
console.log(`Dropped ${source.data.id} onto ${id}`)
},
})
)
}, [id])
return <div ref={ref}>{label}</div>
}
The Pragmatic DnD philosophy:
- No React dependency in the core (framework-agnostic)
- No animation opinions — build your own with any library
- No position calculation assumptions — you decide what "drop here" means
- Platform-specific adapters: element, text, files, external sources
- Native drag events only — maximum browser compatibility
Why Atlassian chose this approach:
At Jira/Trello scale, even small performance regressions matter. By removing ALL abstractions, Pragmatic DnD gives you direct access to browser drag events with minimal JavaScript overhead.
Feature Comparison
| Feature | @dnd-kit | Pragmatic DnD | react-beautiful-dnd |
|---|---|---|---|
| Bundle size (core) | 6KB | 3.5KB | 30KB |
| Maintenance | ✅ Active | ✅ Active | ❌ Deprecated |
| React dependency | Yes | Optional | Yes |
| Built-in animations | Via transforms | ❌ DIY | ✅ Yes |
| Sortable preset | ✅ @dnd-kit/sortable | ❌ DIY | ✅ Yes |
| Multi-container | ✅ Built-in | ✅ Manual | ✅ Built-in |
| Accessibility | ✅ Excellent | ✅ Via helpers | ✅ Excellent |
| TypeScript | ✅ First-class | ✅ First-class | ⚠️ Bolted on |
| Virtual lists | ✅ Supported | ✅ Designed for it | ⚠️ Hacky |
| File drag-and-drop | ❌ Elements only | ✅ Built-in adapter | ❌ |
| External drag sources | ❌ | ✅ Built-in adapter | ❌ |
| Framework agnostic | ❌ React-only | ✅ Yes | ❌ React-only |
When Virtual Lists Matter
For long sortable lists (hundreds to thousands of items), @dnd-kit pairs well with virtual list libraries:
import { useVirtualizer } from "@tanstack/react-virtual"
import { SortableContext, verticalListSortingStrategy } from "@dnd-kit/sortable"
function VirtualSortableList({ items }: { items: string[] }) {
const parentRef = useRef<HTMLDivElement>(null)
const virtualizer = useVirtualizer({
count: items.length,
getScrollElement: () => parentRef.current,
estimateSize: () => 50,
})
return (
<DndContext collisionDetection={closestCenter}>
<SortableContext items={items} strategy={verticalListSortingStrategy}>
<div ref={parentRef} style={{ height: 400, overflow: "auto" }}>
<div style={{ height: virtualizer.getTotalSize() }}>
{virtualizer.getVirtualItems().map((virtualItem) => (
<SortableItem
key={items[virtualItem.index]}
id={items[virtualItem.index]}
style={{ position: "absolute", top: virtualItem.start }}
/>
))}
</div>
</div>
</SortableContext>
</DndContext>
)
}
Pragmatic DnD was specifically designed with virtual lists in mind — its core doesn't need to know about all items upfront.
Migration: react-beautiful-dnd → @dnd-kit
// Before (react-beautiful-dnd):
import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd"
function Before({ items }: { items: Item[] }) {
return (
<DragDropContext onDragEnd={handleDragEnd}>
<Droppable droppableId="list">
{(provided) => (
<ul {...provided.droppableProps} ref={provided.innerRef}>
{items.map((item, index) => (
<Draggable key={item.id} draggableId={item.id} index={index}>
{(provided) => (
<li
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
>
{item.label}
</li>
)}
</Draggable>
))}
{provided.placeholder}
</ul>
)}
</Droppable>
</DragDropContext>
)
}
// After (@dnd-kit):
import { DndContext, closestCenter } from "@dnd-kit/core"
import { SortableContext, useSortable } from "@dnd-kit/sortable"
import { CSS } from "@dnd-kit/utilities"
function SortableItem({ item }: { item: Item }) {
const { attributes, listeners, setNodeRef, transform, transition } =
useSortable({ id: item.id })
return (
<li
ref={setNodeRef}
style={{ transform: CSS.Transform.toString(transform), transition }}
{...attributes}
{...listeners}
>
{item.label}
</li>
)
}
function After({ items }: { items: Item[] }) {
return (
<DndContext collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
<SortableContext items={items.map(i => i.id)}>
<ul>
{items.map((item) => (
<SortableItem key={item.id} item={item} />
))}
</ul>
</SortableContext>
</DndContext>
)
}
Key differences in migration:
- No
placeholderelements needed - No
render proppattern — hooks instead onDragEndevent shape is different — usearrayMovefrom @dnd-kit/sortable
When to Use Each
Choose @dnd-kit if:
- You want a React drag-and-drop solution that handles 90% of use cases
- You need sortable lists, kanban boards, or grid reordering
- Keyboard accessibility and screen reader support are priorities
- You want community examples, integrations, and recipes
Choose Pragmatic drag-and-drop if:
- You're building something that looks like Jira, Trello, or Confluence
- You need to drag files or text from outside the browser
- You want maximum control with no abstraction opinions
- Your team has capacity to build animation and collision logic from scratch
- Performance is critical at thousands-of-items scale
Don't use react-beautiful-dnd if:
- Starting a new project in 2026
- You want security patches or React 19 support
Methodology
Download data from npm registry (weekly average, February 2026). Bundle sizes from bundlephobia for core packages. API examples reflect latest stable versions (@dnd-kit 6.x, @atlaskit/pragmatic-drag-and-drop 1.x).