react-dnd vs react-beautiful-dnd vs react-sortablejs
Reactアプリケーションにおけるドラッグ&ドロップライブラリの選定
react-dndreact-beautiful-dndreact-sortablejs類似パッケージ:

Reactアプリケーションにおけるドラッグ&ドロップライブラリの選定

react-beautiful-dndreact-dndreact-sortablejs はすべて React 向けのドラッグ&ドロップ(DnD)機能を提供するライブラリですが、設計思想や対応範囲、実装方法に大きな違いがあります。react-beautiful-dnd は主にリストやグリッド内のアイテム再配置に特化し、物理的なアニメーションとアクセシビリティを重視した設計です。react-dnd はより汎用的な DnD フレームワークで、任意のコンポーネント間でのデータ転送や複雑なドロップロジックをサポートします。一方、react-sortablejs は既存の JavaScript ライブラリである SortableJS を React でラップしたもので、シンプルなソート操作に焦点を当てています。

npmのダウンロードトレンド

3 年

GitHub Starsランキング

統計詳細

パッケージ
ダウンロード数
Stars
サイズ
Issues
公開日時
ライセンス
react-dnd3,430,53521,638231 kB474-MIT
react-beautiful-dnd2,020,16134,0361.39 MB643-Apache-2.0
react-sortablejs293,2432,16974.1 kB109-MIT

React向けドラッグ&ドロップライブラリ比較:react-beautiful-dnd vs react-dnd vs react-sortablejs

Reactでドラッグ&ドロップ(DnD)機能を実装する際、react-beautiful-dndreact-dndreact-sortablejs はよく検討される3つの選択肢です。それぞれ設計目標が異なり、適切な選択はアプリケーションの要件に大きく依存します。この記事では、実際のコードを交えながら、技術的観点から深く比較します。

🧩 基本的な使い方とアーキテクチャ

react-beautiful-dnd

このライブラリは「リスト内でのアイテム移動」に特化しており、1つの <DragDropContext> 内で複数の <Droppable>(ドロップ可能な領域)と <Draggable>(ドラッグ可能なアイテム)を管理します。内部で独自の物理エンジンを用いてアニメーションを制御し、アクセシビリティ(キーボード操作、ARIA属性)を標準でサポートしています。

import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';

function App() {
  const [items, setItems] = useState(['A', 'B', 'C']);

  const onDragEnd = (result) => {
    if (!result.destination) return;
    const newItems = Array.from(items);
    const [reorderedItem] = newItems.splice(result.source.index, 1);
    newItems.splice(result.destination.index, 0, reorderedItem);
    setItems(newItems);
  };

  return (
    <DragDropContext onDragEnd={onDragEnd}>
      <Droppable droppableId="list">
        {(provided) => (
          <ul {...provided.droppableProps} ref={provided.innerRef}>
            {items.map((item, index) => (
              <Draggable key={item} draggableId={item} index={index}>
                {(provided) => (
                  <li
                    ref={provided.innerRef}
                    {...provided.draggableProps}
                    {...provided.dragHandleProps}
                  >
                    {item}
                  </li>
                )}
              </Draggable>
            ))}
            {provided.placeholder}
          </ul>
        )}
      </Droppable>
    </DragDropContext>
  );
}

react-dnd

react-dnd は「DnDのためのフレームワーク」であり、任意のコンポーネントをドラッグ可能またはドロップ可能にすることができます。useDraguseDrop というカスタムフックを使って、各コンポーネントの振る舞いを宣言的に定義します。データ転送は「アイテム型(type)」と「ペイロード(item)」で抽象化され、複雑なロジックも表現可能です。

import { useDrag, useDrop } from 'react-dnd';

const ItemTypes = { CARD: 'card' };

function DraggableItem({ id, text, moveItem }) {
  const [{ isDragging }, drag] = useDrag(() => ({
    type: ItemTypes.CARD,
    item: { id, text },
    collect: (monitor) => ({
      isDragging: !!monitor.isDragging(),
    }),
  }));

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

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

  return (
    <div ref={drop} style={{ backgroundColor: isOver ? '#f0f0f0' : '#fff' }}>
      Drop here
    </div>
  );
}

react-sortablejs

react-sortablejs は、人気のある vanilla JavaScript ライブラリである SortableJS を React コンポーネントとしてラップしたものです。React の状態と直接同期するわけではなく、DOM 操作ベースで動作します。そのため、簡単なユースケースでは非常に手軽ですが、複雑な状態管理との連携には注意が必要です。

import { ReactSortable } from 'react-sortablejs';

function App() {
  const [items, setItems] = useState([
    { id: '1', name: 'A' },
    { id: '2', name: 'B' },
    { id: '3', name: 'C' }
  ]);

  return (
    <ReactSortable
      list={items}
      setList={setItems}
      tag="ul"
    >
      {items.map(item => (
        <li key={item.id}>{item.name}</li>
      ))}
    </ReactSortable>
  );
}

🔄 状態管理との統合

react-beautiful-dnd

状態更新は onDragEnd コールバック内で明示的に行います。リストの変更は開発者が配列操作で実装する必要がありますが、その分、Redux や Zustand などの外部状態管理ライブラリとの統合が容易です。ただし、React の strict mode 下で二重レンダリングが発生すると、一時的なUIのちらつきが起こることがあります(公式ドキュメントで言及されています)。

react-dnd

状態管理は完全に開発者に委ねられます。useDraguseDrop は単に DnD のインタラクションをフックとして提供するだけで、データの更新は drop イベントハンドラ内で自由に記述できます。この柔軟性により、複雑な状態遷移や非同期処理も自然に組み込めます。

react-sortablejs

ReactSortable コンポーネントは listsetList プロパティを通じて React の状態と同期します。内部で SortableJS の onChange イベントを監視し、リストの順序が変わると setList を呼び出します。ただし、リスト項目の内容が変更された場合(例:名前編集)、SortableJS がそれを検知しないため、手動で再マウントや強制更新が必要になることがあります。

📱 アクセシビリティとモバイル対応

react-beautiful-dnd

アクセシビリティはコア設計原則の一つです。キーボードによるフォーカス移動、スペースキーでのドラッグ開始、矢印キーでの位置調整などが標準でサポートされています。また、タッチデバイスでも問題なく動作します(内部で pointer events を使用)。

react-dnd

アクセシビリティは開発者の責任です。HTML5 バックエンドを使用する場合、ネイティブの DnD はスクリーンリーダーとの互換性が低く、タッチデバイスでも動作しません。しかし、touch-backend を別途導入することでモバイル対応は可能ですが、アクセシビリティ対応は自分で実装する必要があります。

react-sortablejs

SortableJS 自体がタッチデバイスをサポートしていますが、キーボード操作や ARIA 属性の自動付与といったアクセシビリティ機能は含まれていません。必要に応じて、開発者が追加で実装する必要があります。

⚙️ 複雑なユースケースへの対応

複数のリスト間でのアイテム移動

  • react-beautiful-dnd: DroppabledroppableId を使って複数のリストを識別し、onDragEndsource.droppableIddestination.droppableId を比較して移動先を判定します。
const onDragEnd = (result) => {
  const { source, destination } = result;
  if (!destination) return;

  if (source.droppableId === destination.droppableId) {
    // 同一リスト内での並べ替え
  } else {
    // 異なるリスト間での移動
  }
};
  • react-dnd: useDropaccept オプションで受け入れるアイテム型を指定し、異なるコンポーネント間でデータをやり取りできます。さらに、canDrop を使ってドロップ可否を動的に制御できます。

  • react-sortablejs: group オプションを同じ値に設定することで、複数のリスト間でのアイテム移動を有効にできます。

<ReactSortable group="shared" list={list1} setList={setList1} />
<ReactSortable group="shared" list={list2} setList={setList2} />

条件付きドロップ(例:特定のアイテムのみ許可)

  • react-beautiful-dnd: onDragEnd 内で条件をチェックし、条件に合わない場合は何もしない(元の位置に戻す)ことで実現します。

  • react-dnd: useDropcanDrop 関数で条件を定義できます。これにより、ドロップゾーンの見た目(例:色変更)も動的に変更可能です。

const [{ canDrop, isOver }, drop] = useDrop(() => ({
  accept: ItemTypes.CARD,
  canDrop: (item) => item.type !== 'locked',
  drop: (item) => { /* ... */ },
  collect: (monitor) => ({
    isOver: !!monitor.isOver(),
    canDrop: !!monitor.canDrop(),
  }),
}));
  • react-sortablejs: onMove オプションで移動可否を制御できます。
<ReactSortable
  onMove={(evt) => {
    // evt.dragged でドラッグ中の要素を参照
    // false を返すと移動をキャンセル
    return evt.dragged.dataset.type !== 'locked';
  }}
/>

⚠️ 注意点と制限

react-beautiful-dnd

  • メンテナンス状況: 公式 GitHub リポジトリ(atlassian/react-beautiful-dnd)は 2021 年以降、新機能の開発が停止されており、バグ修正のみが行われています。新しいプロジェクトでは代替手段の検討を推奨します。
  • 制限事項: ネストされた DnD コンテキスト(例:カード内のリスト)はサポートされていません。また、仮想化(react-window など)との併用は非公式のワークアラウンドが必要です。

react-dnd

  • 学習コスト: コンセプト(Backend、Monitor、Collector など)を理解するのに時間がかかる場合があります。
  • パフォーマンス: 大量のドラッグ可能要素がある場合、各要素が個別のフックを持つため、メモ化や最適化が必要になることがあります。

react-sortablejs

  • React との整合性: DOM 操作ベースのため、React の仮想DOMと競合することがあります。特に、リスト項目が複雑な子コンポーネントを持つ場合、状態の不整合が起きやすいです。
  • TypeScript サポート: 型定義はコミュニティ提供のものであり、公式サポートではありません。

📊 まとめ:どのライブラリを選ぶべきか

要件推奨ライブラリ
シンプルなリストの並べ替えreact-sortablejs
洗練されたUIとアクセシビリティreact-beautiful-dnd(※新規プロジェクトでは注意)
複雑なDnDロジック(条件付きドロップ、複数型のアイテムなど)react-dnd
長期保守が見込まれる大規模アプリreact-dnd
最小限のセットアップで素早く実装react-sortablejs

💡 最終的なアドバイス

  • 新規プロジェクトでリストの並べ替えだけが必要ならreact-sortablejs が最も手軽です。ただし、将来的に要件が複雑化する可能性があるなら、最初から react-dnd を検討してもよいでしょう。
  • react-beautiful-dnd は既存プロジェクトでの維持には使えますが、新規プロジェクトでは代替手段を検討することを強く推奨します。Atlassian 社自身が新しい DnD ライブラリを開発中であることが公表されています。
  • 最大の柔軟性と将来性を求めるならreact-dnd が最も堅実な選択です。初期設定はやや面倒ですが、一度慣れればあらゆる DnD シナリオに対応できます。

どのライブラリを選ぶにせよ、ユーザー体験(特にアクセシビリティとモバイル対応)を常に意識することが重要です。

選び方: react-dnd vs react-beautiful-dnd vs react-sortablejs

  • react-dnd:

    react-dnd は、複雑な DnD シナリオ(例:ツールボックスからキャンバスへの要素配置、異なる型のアイテム間での条件付きドロップなど)を実装する必要がある場合に適しています。HTML5 DnD API を抽象化しつつ、柔軟なバックエンド(HTML5、Touch、Test など)をサポートしており、大規模・長期運用が見込まれるアプリケーションに適しています。ただし、基本的なリストの並べ替えだけであれば、設定がやや冗長になる可能性があります。

  • react-beautiful-dnd:

    react-beautiful-dnd は、リストやボード内でのアイテムの並べ替えや移動に特化した UI を構築したい場合に最適です。特に、スムーズなアニメーション、キーボード操作対応、タッチデバイス対応など、ユーザー体験とアクセシビリティを重視するプロジェクトに向いています。ただし、複数の DnD コンテキスト間でのアイテム移動や、カスタムデータペイロードの転送といった高度なユースケースには向いていません。

  • react-sortablejs:

    react-sortablejs は、シンプルかつ軽量にリストの並べ替え機能を実装したい場合に有効です。SortableJS の豊富なオプション(グループ間移動、フィルタリング、イベントフックなど)をそのまま利用でき、学習コストが低く、素早くプロトタイプを作成できます。ただし、React のライフサイクルとの統合が完全ではなく、状態管理との同期に注意が必要です。また、アクセシビリティやアニメーションの品質は他の2つに劣ります。

react-dnd のREADME

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.