以下の内容はhttps://tech.smarthr.jp/entry/2025/01/27/143120より取得しました。


dnd kitを使った並べ替えUI実装の課題と解決策

dnd kitを使った並べ替えUI実装の課題と解決策

こんにちは、SmartHR の基本機能の開発を担当しているプロダクトエンジニアの sakata です。 現在、ドラッグ&ドロップで要素を並べ替えられる UI の開発を進めています。

この機能の実装にあたり、ドラッグ&ドロップのライブラリには dnd kit を採用しています。

今回は、 dnd kit を使い、入力フォーム内の複数の入力要素をドラッグ&ドロップで並べ替えができるUIを実装する際に直面した課題とその解決方法について解説します。

dnd kit とは

dnd kit は、React 向けの軽量かつ柔軟なドラッグ&ドロップライブラリです。直感的な API 設計と高いカスタマイズ性が特徴で、シンプルな並べ替えから複雑な UI 構築まで幅広く対応できます。また、アクセシビリティに配慮されており、キーボード操作やスクリーンリーダーもサポートしています。 (ChatGPT に説明していただきました。)

実現したい UI

以下の図は、今回開発した UI を簡略化したものです。

実現したいUI

入力フォームが含まれている要素があり、ユーザーはマウスのドラッグ&ドロップもしくはキーボード操作で要素を並べ替えることができます。

この UI を実現するためのコードは長いため割愛しますが、ベースは「Sortable | @dnd-kit – Documentation」の「Overview」に記載されたコードです。

実現したい UI を実装する過程で2つの課題に遭遇しました。 遭遇した課題とその原因と解決策について解説します。

課題その1: 入力フォーム内のテキストをドラッグで選択できない

事象

入力フォームに入力されたテキストをマウスのドラッグ操作で選択できないという事象が起きました。

入力フォーム内のテキストをドラッグで選択できない

原因と解決策

原因は、テキストをドラッグしようとした際に、 dnd kit の並べ替え処理による要素を掴む操作が優先されてしまうことでした。

解決策は、 input 要素の onMouseDown イベントが発行されたときに、親要素へのイベントの伝播を止める stopPropagation() メソッドを呼ぶことです。 stopPropagation() を使用して、 input 要素内の onMouseDown イベントが DndContext に伝搬しないようにすることで、テキストをマウスのドラッグ操作で選択できるようになりました。

<input
  onMouseDown={(e) => {
    e.stopPropagation();
  }}
/>

課題その2: 入力フォームに日本語を入力すると並べ替えができなくなる

事象

入力要素に日本語を入力すると、マウス操作による要素の並べ替えができなくなるという事象が起きました。

入力フォームに日本語を入力すると並べ替えできなくなる

原因と解決策

日本語を入力した際に押下する、変換を確定するためのエンターキーが原因でした。

キーボード操作によるドラッグ&ドロップを可能にする KeyboardSensor を使用している場合、スペースキーとエンターキーの押下が、ドラッグ&ドロップモードの開始イベントになります。

// ref: https://docs.dndkit.com/api-documentation/sensors/keyboard#keyboard-codes
const defaultKeyboardCodes = {
  start: ['Space', 'Enter'],
  cancel: ['Escape'],
  end: ['Space', 'Enter'],
};

キーボード操作によるドラッグ&ドロップモードになっていて、マウス操作による並べ替えが機能しなくなっているという現象でした。

この現象を解決する方法として、まず以下の2つの案が考えられました。

  1. KeyboardSensor を使わない(キーボード操作による並べ替えを諦める)
  2. エンターキーをドラッグ&ドロップモードの開始イベントから外す

しかしながら、キーボード操作で並べ替えができることは要件に含まれているため、1つ目の案は採用できません。 また、2つ目のエンターキーをドラッグ&ドロップモードの開始イベントから外す案は、アクセシビリティに関するルールを定めている ARIA の、キーボード操作に関するルールを満たすことができなくなるため採用したくありません。このことは dnd kitのドキュメント にも記載があります。

You can customize these values, but keep in mind that the third rule of ARIA requires that a user must be able to activate the action associated with a draggable widget using both the enter (on Windows) or return (on macOS) and the space key. To learn more, read the in-depth accessibility guide.

そのため、他の解決案を探した結果、今回は入力要素の onKeyDown イベント発火時に、押されたキーがエンターキーだった場合は、 preventDefault() を実行し、ドラッグ&ドロップモードになる動作がキャンセルされるようにしました。 これにより、入力要素以外にフォーカスが当たった状態でエンターキーを押下した場合は、ドラッグ&ドロップモードになるという動作が実現できました。

<input
  onKeyDown={(e) => {
    if (e.key === 'Enter') {
      e.preventDefault()
    }
  }
/>

おわりに

今回は dnd kit を使った入力要素を含む要素の並べ替え UI の実装時に遭遇した課題と解決策について解説しました。 本記事が、同じ現象でお困りの方の解決の一助になれば幸いです。

We Are Hiring!

SmartHR では一緒に SmartHR を作りあげていく仲間を募集中です!

少しでも興味を持っていただけたら、カジュアル面談でざっくばらんにお話ししましょう!

hello-world.smarthr.co.jp




以上の内容はhttps://tech.smarthr.jp/entry/2025/01/27/143120より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14