EmpireUI
Get Pro
← Blog8 min read#drag drop#react#dnd-kit

Drag and Drop in React 2026: dnd-kit vs react-beautiful-dnd

dnd-kit or react-beautiful-dnd? In 2026 one is actively maintained and one isn't. Here's the honest breakdown to help you pick the right library.

Developer coding drag and drop React UI on a laptop screen

The State of React Drag and Drop in 2026

If you've shipped a Kanban board, a sortable list, or a file upload zone in the last three years, you've probably asked this question: dnd-kit or react-beautiful-dnd? Short answer — dnd-kit. Longer answer follows.

react-beautiful-dnd was the gold standard back in 2019. Atlassian built it for Jira, it looked gorgeous out of the box, and the API felt like it was designed by humans. That said, Atlassian officially stopped active development on it in 2022, and by 2026 the issues tab is a graveyard of unanswered React 18 compatibility bugs and concurrent mode complaints.

dnd-kit, by contrast, shipped its v6 in late 2024 with full React 19 support, a proper accessibility tree, and a modular architecture that doesn't shove 40 kb of code into your bundle if you only need sortable lists. It's now the default recommendation in most serious React projects.

Worth noting: neither library is "the only option." If you're building something wildly custom — think a node-based visual editor or a 2D canvas — you might want to roll a lower-level solution with the Pointer Events API directly. But for 95% of product work, you want dnd-kit.

Why react-beautiful-dnd Is Effectively Dead

Look, I don't enjoy writing obituaries for libraries I've used happily. But you need to know this before you start a new project. react-beautiful-dnd hasn't had a meaningful release since version 13.1.1 in 2022, and its peer dependency still lists react: ^16.8.0 || ^17.0.0. That should tell you everything.

The real pain shows up with React 18's concurrent rendering. react-beautiful-dnd uses ReactDOM.findDOMNode() internally, which was deprecated in React 18 and removed in React 19. If you're on a modern stack, you'll hit warnings in dev mode and subtle breakage in production. Not ideal.

In practice, you'll also notice the performance ceiling fast. Drop a list of 500+ items and the re-render cascade becomes visible at 60fps. dnd-kit's virtual list support handles that cleanly because it was designed with performance as a first-class concern, not an afterthought.

Quick aside: if you're already maintaining a codebase that uses react-beautiful-dnd and a migration isn't justified right now, that's fine. Just don't start new features with it.

Getting Started with dnd-kit

Installation is one line. Nothing fancy here.

npm install @dnd-kit/core @dnd-kit/sortable @dnd-kit/utilities

The mental model is three layers: DndContext wraps everything and owns the drag state. SortableContext tells dnd-kit which items are sortable and in what order. Individual useSortable hooks attach to each item. That separation is clean and it means you can mix sortable and non-sortable drop zones in the same context without fighting the library.

Here's a minimal sortable list — the kind you'd use for a Kanban column or a settings panel with reorderable rows:

import { useState } from 'react';
import {
  DndContext,
  closestCenter,
  PointerSensor,
  useSensor,
  useSensors,
} from '@dnd-kit/core';
import {
  arrayMove,
  SortableContext,
  useSortable,
  verticalListSortingStrategy,
} from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';

function SortableItem({ id }) {
  const { attributes, listeners, setNodeRef, transform, transition } =
    useSortable({ id });

  const style = {
    transform: CSS.Transform.toString(transform),
    transition,
    padding: '12px 16px',
    marginBottom: '8px',
    background: '#1e1e2e',
    borderRadius: '8px',
    cursor: 'grab',
    userSelect: 'none',
  };

  return (
    <div ref={setNodeRef} style={style} {...attributes} {...listeners}>
      {id}
    </div>
  );
}

export function SortableList() {
  const [items, setItems] = useState(['Task A', 'Task B', 'Task C', 'Task D']);

  const sensors = useSensors(useSensor(PointerSensor, {
    activationConstraint: { distance: 8 }, // px before drag starts
  }));

  function handleDragEnd(event) {
    const { active, over } = event;
    if (active.id !== over?.id) {
      setItems((items) => {
        const oldIndex = items.indexOf(active.id);
        const newIndex = items.indexOf(over.id);
        return arrayMove(items, oldIndex, newIndex);
      });
    }
  }

  return (
    <DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
      <SortableContext items={items} strategy={verticalListSortingStrategy}>
        {items.map((id) => <SortableItem key={id} id={id} />)}
      </SortableContext>
    </DndContext>
  );
}

That activationConstraint: { distance: 8 } is worth explaining. Without it, a single click fires the drag handlers and your click events stop working on interactive list items like buttons or inputs. 8px is the sweet spot — enough to distinguish an intentional drag from an accidental tap. You'll thank yourself later.

Sensors, Collision Detection, and the Bits That Actually Trip People Up

dnd-kit ships three sensors: PointerSensor, KeyboardSensor, and TouchSensor. Most of the time you want Pointer for mouse/touch and Keyboard for accessibility. Stack them with useSensors and pass the array to DndContext.

Collision detection is where you'll spend more time than you expect. closestCenter works for most lists. But if you're building a Kanban board where cards drop into columns, closestCorners gives you more intuitive snapping behavior — it measures the distance from the dragged item's corners to the target's corners instead of centers, which matters a lot when items have varying heights.

One more thing — the DragOverlay component. It's optional but you almost always want it. By default, the dragged item stays in the DOM and just visually moves. That can cause layout shifts and weird z-index issues. DragOverlay renders the dragged item into a portal at the root level, so it always sits above everything else with no stacking context problems. Pair it with an onDragStart handler that sets the active item in state, render that item inside DragOverlay, done.

Honestly, the biggest footgun in dnd-kit is forgetting that item IDs must be strings or numbers and must be unique across the entire DndContext — not just within a single list. If you've got two Kanban columns where both contain an item with id 1, you'll get silent misbehavior that's genuinely hard to trace.

Accessibility: the Part Everyone Skips

Drag and drop is notoriously hostile to keyboard users and screen reader users. That's not a small deal — in the US, accessibility compliance under WCAG 2.1 AA is a legal consideration for plenty of products, especially anything enterprise-facing.

dnd-kit ships KeyboardSensor with sensible defaults: arrow keys move items, Space picks up and drops, Escape cancels. It also generates appropriate aria-roledescription, aria-describedby, and live region announcements automatically. You do still need to wire up the screenReaderInstructions and announcements props on DndContext if you want custom messaging, but the defaults are genuinely usable.

react-beautiful-dnd was actually ahead of dnd-kit on this back in 2019. The keyboard support was excellent. That legacy advantage doesn't help you in 2026 when the whole library is unmaintained, but it's worth acknowledging the work Atlassian put in.

If your product has real accessibility requirements, test dnd-kit with VoiceOver or NVDA before shipping. The library does the heavy lifting, but your implementation details — things like whether the drag handle has a visible focus ring at outline-offset: 2px — still matter. Check out Empire UI's component library for accessible interactive patterns if you need reference implementations.

When You Might Skip Both and Use Something Else

Both libraries are great for list sorting and card-based layouts. Neither is the right tool for everything. If you're building a node graph editor, a drag-to-resize panel layout, or a 2D design canvas — think templates with complex interactive zones — you're probably better served by a specialized tool.

For node editors, @xyflow/react (formerly React Flow) owns that space. For resizable panels, react-resizable-panels from Bryan Vaughn is purpose-built and composable. For file upload drop zones specifically, react-dropzone is lighter and more focused than either dnd library.

That said, dnd-kit is surprisingly extensible. The modifier system lets you constrain drag axes, snap to grid, or restrict movement to a container. The collision detection API is pluggable — you can write a custom algorithm that hits a backend for real-time position validation if you really need that. It's not a toy library.

One more thing — bundle size. @dnd-kit/core is around 10 kb gzipped. react-beautiful-dnd is closer to 24 kb. If you're building a page where drag and drop is a secondary feature, that difference matters for initial load time.

The Verdict

Use dnd-kit. It's maintained, it works with React 19, the bundle is lean, and the API is flexible enough to handle most production requirements without fighting the abstractions. Start with @dnd-kit/core and @dnd-kit/sortable — you likely don't need the full suite upfront.

If you're migrating from react-beautiful-dnd, the concepts map fairly cleanly. Droppable + Draggable becomes SortableContext + useSortable. The onDragEnd result object is structured differently but carries the same information. A medium-complexity Kanban board migration usually takes a day or two.

For the visual layer, remember that drag-and-drop interactions are a great opportunity to lean into motion design. Smooth 200ms transitions on transform and opacity, a subtle scale on the active drag item, a highlight on the drop target. It's not decorative — it communicates state. If you want to see what polished interactive UI looks like, browse the Empire UI component library or check out the glassmorphism components for inspiration on layered UI patterns.

Whichever library you pick, test it on mobile. Touch interactions on iOS and Android have different timing characteristics than mouse events, and the gap between "works on desktop" and "works on a 375px iPhone" is wider than you'd expect for drag and drop specifically.

FAQ

Is react-beautiful-dnd still safe to use in 2026?

Technically it runs, but it's unmaintained and breaks with React 19 due to the deprecated ReactDOM.findDOMNode() dependency. Don't start new projects with it.

Can dnd-kit handle multi-list drag and drop like a Kanban board?

Yes — you nest multiple SortableContext instances inside one DndContext and track which container the active item is over via onDragOver. The official docs have a working multi-container example.

Does dnd-kit work with React Server Components?

The drag hooks require client components since they rely on DOM APIs and event listeners. Mark your drag-enabled components with 'use client' and you're fine.

What's the performance ceiling on dnd-kit with large lists?

Vanilla dnd-kit re-renders the full list on drag. For 500+ items you'll want to combine it with @dnd-kit/sortable's virtualized strategy alongside a windowing library like react-virtual to avoid layout thrash.

Free components in 40 styles
React & Tailwind, copy-paste ready.
Browse →

Read next

Drag-and-Drop Kanban in React: dnd-kit Full ImplementationDrag-and-Drop in React with dnd kit: Sortable, Multi-ContainerKanban Board in React: Drag-and-Drop Columns With dnd-kitFile Upload in React: Drag & Drop, Progress Bar and Validation