DnDについて - React Ariaの実装読むぞ
こんにちは、フロントエンドエンジニアの mehm8128 です。
今日は DnD について書いていきます。
本題
DnD
React Aria では Drag and Drop (DnD)の a11y 対応も行われています。
それがこれらのページにまとめられています。
DnD はマウスやタッチによる操作を前提としているように思われるかもしれませんが、DnD によって行いたい操作を、同様の異なる操作によって実現できていれば問題ありません。そこで、React Aria ではキーボード操作によって DnD と同様の操作、つまりアイテムの移動ができるようになっています。また、初めてそのサービスを使うユーザーにとってはそのキーボード操作方法が分からない可能性もあるということで、アナウンスによる操作方法の補足説明も行われます。
DnD は主にuseDrag
とuseDrop
を用いて連携させることによって実現できます。ドラッグできるアイテム(drag source)にuseDrag
、ドロップできる箇所(drop target)にuseDrop
を用います。
また、ListBox や GridList などのリスト内で用いるにはuseDraggableCollection
やuseDroppableCollection
を使います。
しかし、例えばファイルアップロードなどといった外部アプリケーションと連携するような DnD 操作を考えてみます。マウスによって DnD を行うことができるユーザーであれば DropZone のようなものを用意しておくことで DnD が可能ですが、キーボード操作しか行うことのできないユーザーはこれを用いることができません(useDrag
などは実装している Web アプリ内で完結してしまう機能であるため)。これらを実現可能にするために、useClipboard
という hook も提供されています。これは内部でClipboard API - Web APIs | MDNを使用していて、外部アプリケーションとも連携可能になります。
Clipboard API については、最近会社の先輩が記事を出していたので興味のある方は読んでみてください。
それでは実装を見ていきましょう。
DragSession
というオブジェクトでドラッグ中のキーボード操作の listener 登録や、それに伴うスクリーンリーダー用アナウンスが設定されています。
そしてDragSession
はuseDrag
内のstartDragging
関数内で初期化されています。アナウンステキストの翻訳用のstringFomatter
もここで渡されています。
アナウンステキストをいくつか見ていきます。
useDrag
内では drag source に対するラベルのみ付与しています。例えばキーボード操作でフォーカスした場合(modality === 'keyboard'
の場合)(以降アナウンスの例はこの場合のテキストを紹介します)、「Enter キーを押してドラッグを開始してください。」「ドラッグしています。Enter キーを押してドラッグをキャンセルします。」というテキストが accessible description に与えられます。
上記のbeginDragging
関数内で実行されるsetup
メソッドで、ドラッグが開始されたときに「ドラッグを開始します。Tab キーを押してドロップターゲットに移動し、Enter キーを押してドロップするか、Esc キーを押してキャンセルします。」などのアナウンスをします。
次にuseDropIndicator
を見ていきます。これは、ドラッグ中にリストのアイテムとアイテムの間に表示されるバーのようなものです。最初に紹介したブログ記事のデモでも体験できます。
これはbutton
role になっているのですが、リスト内でリストアイテム以外の要素が出てくることは通常ないので、aria-roledescription
に「ドロップインジケーター」というテキストが指定され、役割が明確にされています。
この Indicator にもアナウンス対応がされていて、矢印キーなどでフォーカスを移動したときに「{beforeItemText} と {afterItemText} の間に挿入」(プレイスホルダーにはアイテムのラベルが入る)などのアナウンスがされます。
DnD は実装が重く、色々な実現方法があると考えられることもあり、先に RFC が出されていました。今回は要約などはしないので紹介だけしておきます。
https://github.com/adobe/react-spectrum/blob/main/rfcs/2020-v3-dnd.md
まとめ
明日の担当は @mehm8128 さんで、まとめの記事です。お楽しみにー
Discussion