tabindex を使って DOM の順序を変更する

Dave Gash
Dave Gash
Meggin Kearney
Meggin Kearney
Alexandra Klepper
Alexandra Klepper

セマンティック HTML 要素の DOM 位置によって提供されるデフォルトのタブ順序は便利ですが、タブ順序の変更が必要になる場合があります。HTML で要素を移動することは理想的ですが、現実的ではない可能性があります。このような場合は、tabindex HTML 属性を使用して、要素のタブの位置を明示的に設定できます。

対応ブラウザ

  • 1
  • 12
  • 1.5
  • 4 以下

ソース

tabindex はどの要素にも適用できますが、すべての要素で必ずしも役立つとは限りません。また、整数値の範囲を取ります。tabindex を使用すると、フォーカス可能なページ要素の明示的な順序の指定、通常はフォーカスできない要素をタブオーダーに挿入して、タブオーダーから要素を削除できます。次に例を示します。

tabindex="0": 自然なタブオーダーに要素を挿入します。Tab キーを押すことで要素をフォーカスでき、focus() メソッドを呼び出して要素にフォーカスできます。

tabindex="-1": 自然なタブオーダーから要素を削除しますが、focus() メソッドを呼び出して要素にフォーカスを合わせることは可能です。

tabindex="5": 0 より大きい tabindex を指定すると、その要素が自然なタブオーダーの前に表示されます。tabindex が 0 より大きい要素が複数ある場合は、0 より大きい最小値から順にタブオーダーが上がっていきます。0 より大きい tabindex を使用すると、アンチパターンとみなされます。

これは特に、ヘッダー、画像、記事のタイトルなどの入力以外の要素に当てはまります。可能な場合は、DOM シーケンスが論理的なタブオーダーを提供するようにソースコードを配置することをおすすめします。tabindex を使用する場合は、ボタン、タブ、プルダウン、テキスト フィールドなどのカスタム インタラクティブ コントロール、つまりユーザーが入力を提供する可能性のある要素に限定します。

tabindex はインタラクティブなコンテンツにのみ追加します。主要な画像などのコンテンツが重要な場合でも、スクリーン リーダーのユーザーはフォーカスを追加しなくてもそのコンテンツを理解できます。

ページレベルでフォーカスを管理する

シームレスなユーザー エクスペリエンスを実現するには、tabindex が必要になる場合があります。たとえば、複数のコンテンツ セクションを含む堅牢な単一ページを作成し、すべてのコンテンツが同時に表示されるわけではない場合などです。つまり、ページを更新しなくても、ナビゲーション リンクによって表示されるコンテンツが変更される場合があります。

この場合は、選択したコンテンツ エリアを特定し、tabindex-1 にして、その focus メソッドを呼び出します。これにより、コンテンツが通常のタブオーダーに表示されなくなります。この手法はフォーカスの管理と呼ばれ、ユーザーが認識したコンテキストをサイトのビジュアル コンテンツと同期した状態に維持します。

コンポーネントのフォーカスの管理

場合によっては、カスタム コンポーネントなど、コントロール レベルでもフォーカスを管理する必要があります。

たとえば、select 要素は基本フォーカスを受け取ることができますが、一度フォーカスされると、矢印キーを使用して追加の選択可能なオプションを表示できます。カスタムの select 要素を作成する場合は、その動作を複製して、キーボードのユーザーが引き続きコントロールを操作できるようにすることが重要です。

どのキーボード動作を実装すべきかを判断するのは難しい場合があります。Accessible Rich Internet Applications(ARIA)Authoring Practices ガイドには、コンポーネントのタイプと、コンポーネントがサポートするキーボード操作の種類が記載されています。

たとえば、一連のラジオボタンと似ていながら、外観と動作を独自に変えたカスタム要素を作成している場合です。

<radio-group>
    <radio-button>Water</radio-button>
    <radio-button>Coffee</radio-button>
    <radio-button>Tea</radio-button>
    <radio-button>Cola</radio-button>
    <radio-button>Ginger Ale</radio-button>
</radio-group>

必要なキーボードのサポートを確認するには、ARIA オーサリング実践ガイドをご覧ください。 セクション 2 には、無線グループの特性表(新しい要素に最も近い既存のコンポーネント)などの設計パターンの一覧が記載されています。

サポートすべき一般的なキーボード動作の一つに、上/下/左/右矢印キーがあります。この動作を新しいコンポーネントに追加するには、tabindex の移動と呼ばれる手法を使用します。

tabindex の移動は、現在アクティブな子を除くすべての子に対して tabindex を -1 に設定することで機能します。

<radio-group>
  <radio-button tabindex="0">Water</radio-button>
  <radio-button tabindex="-1">Coffee</radio-button>
  <radio-button tabindex="-1">Tea</radio-button>
  <radio-button tabindex="-1">Cola</radio-button>
  <radio-button tabindex="-1">Ginger Ale</radio-button>
</radio-group>

このコンポーネントは、キーボード イベント リスナーを使用して、ユーザーが押したキーを決定します。この場合、以前にフォーカスされていた子の tabindex を -1 に設定し、フォーカスされる子の tabindex を 0 に設定して、そのフォーカス メソッドを呼び出します。

<radio-group>
    <!-- Assuming the user pressed the down arrow, we'll focus the next available child -->
    <radio-button tabindex="-1">Water</radio-button>
    <radio-button tabindex="0">Coffee</radio-button> // call .focus() on this element
    <radio-button tabindex="-1">Tea</radio-button>
    <radio-button tabindex="-1">Cola</radio-button>
    <radio-button tabindex="-1">Ginger Ale</radio-button>
</radio-group>

ユーザーが最後の子(フォーカスの移動方向によっては最初)に到達すると、フォーカスは最初(または最後)の子にループ戻ります。

次の例を試してみてください。DevTools で要素を調べて、tabindex が 1 つのラジオから次のラジオに移動するのを確認します。

モーダルとキーボード トラップ

複雑な状況が発生する可能性があるため、手動でフォーカスの管理はおすすめしません。たとえば、フォーカスの管理を試み、タブの動作をキャプチャするが、完了するまでユーザーがページを離れることを防ぐ予測入力ウィジェット。これは「キーボード トラップ」と呼ばれ、ユーザーにとって大きなストレスになります。

WCAG のセクション 2.1.2 では、キーボードのフォーカスを特定のページ要素でロックまたはトラップしてはならないと規定されています。ユーザーがキーボードのみを使用して、すべてのページ要素間を移動できるようにします。

このルールの例外はモーダルです。ただし、モーダルの作成時に tabindex を使用することは避けてください。inert を使用すると、ユーザーが誤って要素を操作する(意図的なキーボード トラップ)ことを防止できます。デフォルトで無効になっている <dialog> 要素を使用して、ユーザーのモーダルを作成し、モーダル外でのクリックやタブをブロックします。これにより、ユーザーは必要な選択項目にフォーカスできます。