react-dnd vs react-beautiful-dnd vs react-sortablejs
Drag-and-Drop Libraries for React Applications
react-dndreact-beautiful-dndreact-sortablejsSimilar Packages:

Drag-and-Drop Libraries for React Applications

react-beautiful-dnd, react-dnd, and react-sortablejs are all npm packages that enable drag-and-drop (DnD) functionality in React applications, but they differ significantly in architecture, use cases, and implementation details. react-beautiful-dnd is a high-level, opinionated library focused on vertical and horizontal list reordering with built-in accessibility and physics-based animations. react-dnd is a lower-level, flexible framework that supports arbitrary drag sources and drop targets, ideal for complex interactions like canvas editors or inventory systems. react-sortablejs is a React wrapper around the SortableJS library, offering a lightweight way to add sortable lists with minimal configuration by leveraging an external imperative DOM-manipulation engine.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
react-dnd3,430,53521,638231 kB474-MIT
react-beautiful-dnd034,0361.39 MB643-Apache-2.0
react-sortablejs02,16974.1 kB109-MIT

Drag-and-Drop in React: react-beautiful-dnd vs react-dnd vs react-sortablejs

When you need drag-and-drop in a React app, three main libraries stand out — each with a different philosophy. Let’s compare them based on real engineering trade-offs: how they manage state, handle accessibility, integrate with React, and support common patterns like list reordering or cross-container dragging.

🧩 Core Architecture: Declarative vs Flexible Primitives vs Imperative Wrapper

react-beautiful-dnd uses a fully declarative, React-first model. You describe your draggable items and droppable areas using components (<Draggable>, <Droppable>), and the library manages all DOM mutations, state, and side effects internally. It assumes a specific layout (lists or grids) and enforces constraints to ensure smooth UX.

// react-beautiful-dnd: declarative list
import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';

function TaskList({ tasks, onDragEnd }) {
  return (
    <DragDropContext onDragEnd={onDragEnd}>
      <Droppable droppableId="tasks">
        {(provided) => (
          <div {...provided.droppableProps} ref={provided.innerRef}>
            {tasks.map((task, index) => (
              <Draggable key={task.id} draggableId={task.id} index={index}>
                {(provided) => (
                  <div
                    ref={provided.innerRef}
                    {...provided.draggableProps}
                    {...provided.dragHandleProps}
                  >
                    {task.content}
                  </div>
                )}
              </Draggable>
            ))}
            {provided.placeholder}
          </div>
        )}
      </Droppable>
    </DragDropContext>
  );
}

react-dnd provides flexible primitives via higher-order components or hooks. You define what can be dragged (useDrag) and what can be dropped (useDrop), and manage your own state updates in response to drag events. It doesn’t assume any layout — you can drag anything anywhere.

// react-dnd: flexible drag source and drop target
import { useDrag, useDrop } from 'react-dnd';

const Item = ({ id, moveItem }) => {
  const [{ isDragging }, drag] = useDrag(() => ({
    type: 'item',
    item: { id },
    collect: (monitor) => ({
      isDragging: !!monitor.isDragging(),
    }),
  }));

  return <div ref={drag} style={{ opacity: isDragging ? 0.5 : 1 }}>{id}</div>;
};

const Container = ({ accept, onDrop }) => {
  const [{ isOver }, drop] = useDrop(() => ({
    accept,
    drop: (item) => onDrop(item),
    collect: (monitor) => ({
      isOver: !!monitor.isOver(),
    }),
  }));

  return <div ref={drop} style={{ background: isOver ? '#eee' : '#fff' }} />;
};

react-sortablejs wraps the imperative SortableJS library, which directly manipulates the DOM. You pass configuration options and rely on callbacks to sync changes back to React state. It’s less integrated with React’s rendering cycle and often requires refs or manual state reconciliation.

// react-sortablejs: imperative wrapper
import { ReactSortable } from 'react-sortablejs';

function TaskList({ tasks, setTasks }) {
  return (
    <ReactSortable
      list={tasks}
      setList={setTasks}
      animation={150}
      ghostClass="sortable-ghost"
    >
      {tasks.map((task) => (
        <div key={task.id}>{task.content}</div>
      ))}
    </ReactSortable>
  );
}

♿ Accessibility and Built-in UX

react-beautiful-dnd includes keyboard navigation, screen reader announcements, and auto-scrolling out of the box. It enforces a focus management strategy that works with standard HTML lists, making it WCAG-compliant with zero extra effort.

react-dnd provides no built-in accessibility. You must implement keyboard support, ARIA attributes, and focus management yourself if needed — which adds significant work for compliant UIs.

react-sortablejs inherits basic keyboard support from SortableJS (via space/enter to drag), but screen reader support is limited and not React-aware. You’ll likely need to layer additional ARIA logic for full compliance.

🔄 State Management and React Integration

react-beautiful-dnd expects you to mutate your data only in onDragEnd. During drag, it uses its own internal state to render a “virtual” dragged item, so your React state remains unchanged until the user drops. This avoids unnecessary re-renders and keeps the UI responsive.

// react-beautiful-dnd: update state only on drop
const onDragEnd = (result) => {
  if (!result.destination) return;
  const newTasks = reorder(tasks, result.source.index, result.destination.index);
  setTasks(newTasks);
};

react-dnd gives you full control — you can update state during drag (e.g., for hover previews) or only on drop. However, frequent state updates during drag can cause performance issues if not memoized properly.

// react-dnd: optional state updates during drag
const [{ isOver }, drop] = useDrop(() => ({
  drop: (item) => moveItem(item.id, containerId),
  // You could also call moveItem in 'hover' for live feedback
}));

react-sortablejs mutates the DOM directly and calls setList only after sorting completes. Because it bypasses React’s reconciliation, it can conflict with concurrent rendering (e.g., React 18+ strict mode) and may require useLayoutEffect or careful ref handling to stay in sync.

🧪 Testing and Backend Abstraction

react-dnd stands out with its backend system: you can swap the HTML5 backend for a touch backend (mobile) or a test backend (for unit tests). This makes it easier to write deterministic tests without mocking browser events.

// react-dnd: testing with test backend
import { TestBackend } from 'react-dnd-test-backend';

const manager = createDragDropManager(TestBackend);
// Now simulate drag/drop programmatically

Neither react-beautiful-dnd nor react-sortablejs offer this level of testability. react-beautiful-dnd provides a resetServerContext() utility for SSR but no test backend.

⚠️ Maintenance and Future-Proofing

As of 2024:

  • react-beautiful-dnd is officially deprecated. The maintainers recommend migrating to @dnd-kit for new projects. While it still works, it won’t receive new features or React 18+ concurrent mode fixes.
  • react-dnd is actively maintained, with regular updates and full support for modern React (including hooks and concurrent features).
  • react-sortablejs is maintained, but depends on SortableJS, which has its own release cycle. It works with current React versions but uses an imperative approach that feels less “React-like.”

🛑 Important: Do not start new projects with react-beautiful-dnd. Evaluate @dnd-kit instead if you liked its model.

📊 When to Use Which

ScenarioBest ChoiceWhy
Trello-style board with keyboard supportreact-dnd (or @dnd-kit)react-beautiful-dnd is deprecated; react-dnd offers flexibility with extra work
Simple todo list reorderingreact-sortablejsMinimal code, good enough for basic cases
Diagram editor with free-form draggingreact-dndOnly library that supports arbitrary drop targets and custom drag layers
E-commerce product builder (drag widgets into canvas)react-dndNeeds multiple drag types and dynamic drop zones
Legacy app migration (already using SortableJS)react-sortablejsLow friction if you’re familiar with the underlying library

💡 Final Recommendation

  • If you’re starting today, avoid react-beautiful-dnd due to deprecation. Consider @dnd-kit for a similar experience with active support.
  • Choose react-dnd when you need robust, future-proof DnD with full control — especially for complex or accessibility-critical apps.
  • Pick react-sortablejs only for simple, throwaway UIs where speed of implementation trumps long-term maintainability or deep React integration.

Remember: drag-and-drop seems simple until you hit edge cases like nested containers, touch devices, or keyboard navigation. The right library saves weeks of debugging — choose based on your app’s complexity, not just the demo code.

How to Choose: react-dnd vs react-beautiful-dnd vs react-sortablejs

  • react-dnd:

    Choose react-dnd if you require maximum flexibility—such as dragging elements onto arbitrary drop zones, supporting multiple drag types, or building complex UIs like diagram editors or game inventories. Its backend abstraction (HTML5, touch, test) makes it adaptable across environments. Be prepared to write more boilerplate and handle accessibility manually, as it provides primitives rather than turnkey solutions.

  • react-beautiful-dnd:

    Choose react-beautiful-dnd if you need polished, accessible list reordering (like Trello boards) with smooth animations and strong defaults. It’s ideal when your DnD needs are limited to rearranging items within or between lists, and you want a declarative API that handles edge cases like keyboard navigation and screen reader support out of the box. Avoid it if you need free-form dragging, custom drag previews, or non-list layouts.

  • react-sortablejs:

    Choose react-sortablejs if you need a quick, low-effort way to make lists sortable with minimal code changes, especially if you’re already familiar with SortableJS. It’s well-suited for simple reorder scenarios where you don’t need deep React integration or custom drag logic. Avoid it if you require fine-grained control over the drag lifecycle, React state synchronization without refs, or advanced accessibility features.

README for react-dnd

npm version npm downloads Build Status

React DnD

Drag and Drop for React.

See the docs, tutorials and examples on the website:

http://react-dnd.github.io/react-dnd/

See the changelog on the Releases page:

https://github.com/react-dnd/react-dnd/releases

Big thanks to BrowserStack for letting the maintainers use their service to debug browser issues.