セマンティック HTML 要素の DOM 位置によって提供されるデフォルトのタブ順序は便利ですが、タブ順序を変更する必要がある場合もあります。HTML 内の要素を移動するのが理想的ですが、実現できない場合もあります。このような場合は、tabindex
HTML 属性を使用して、要素のタブ位置を明示的に設定できます。
tabindex
は任意の要素に適用できますが、すべての要素で有用とは限りません。また、整数値の範囲を取ります。tabindex
を使用すると、フォーカス可能なページ要素の明示的な順序を指定したり、通常はフォーカスできない要素をタブオーダーに挿入したり、タブオーダーから要素を削除したりできます。次に例を示します。
tabindex="0"
: 自然なタブオーダーに要素を挿入します。Tab キーを押すと要素にフォーカスが移動し、要素の focus()
メソッドを呼び出すと要素にフォーカスが移動します。
tabindex="-1"
: 自然なタブ順序から要素を削除しますが、要素の focus()
メソッドを呼び出すことで、要素にフォーカスできます。
tabindex="5"
: tabindex が 0
より大きい場合、その要素は自然なタブ順の先頭に移動します。tabindex が 0
より大きい要素が複数ある場合、タブオーダーは 0 より大きい最小値から始まり、値が大きくなるにつれて移動します。
これは、特に見出し、画像、記事のタイトルなどの入力以外の要素に当てはまります。可能な場合は、DOM シーケンスが論理的なタブ順序になるようにソースコードを配置することをおすすめします。tabindex
を使用する場合は、ボタン、タブ、プルダウン、テキスト フィールドなどのカスタムのインタラクティブ コントロールに限定します。つまり、ユーザーが入力を行うことを想定している要素に限定します。
tabindex
はインタラクティブなコンテンツにのみ追加してください。キー画像など、コンテンツが重要な場合でも、フォーカスを追加しなくてもスクリーン リーダーのユーザーはコンテンツを理解できます。
ページレベルでフォーカスを管理する
シームレスなユーザー エクスペリエンスを実現するために、tabindex
が必要な場合があります。たとえば、すべてのコンテンツが同時に表示されない、さまざまなコンテンツ セクションを含む堅牢なシングルページを構築する場合などです。たとえば、ナビゲーション リンクをクリックすると、ページが更新されずに表示されるコンテンツが変更される場合などです。
この場合、選択されたコンテンツ領域を特定し、tabindex
を -1
に設定して、その focus
メソッドを呼び出します。これにより、コンテンツが自然なタブ順序で表示されなくなります。この手法は、フォーカスの管理と呼ばれ、ユーザーが認識するコンテキストをサイトのビジュアル コンテンツと同期させます。
コンポーネントのフォーカスを管理する
カスタム コンポーネントなど、コントロール レベルでフォーカスを管理する必要がある場合もあります。
たとえば、select
要素は基本的なフォーカスを受け取ることができますが、フォーカスされたら、矢印キーを使用して選択可能な追加のオプションを表示できます。カスタム select
要素を構築する場合は、その動作を複製することが重要です。これにより、キーボード ユーザーがコントロールを操作できるようになります。
実装すべきキーボードの動作を把握するのは難しい場合があります。Accessible Rich Internet Applications(ARIA)の作成方法のガイドには、コンポーネントの種類と、それらがサポートするキーボード アクションの種類が記載されています。
ラジオボタンのセットに似た Custom Elements を作成しているとします。外観と動作は独自のものにします。
<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 には、ラジオボタン グループの特性表や、新しい要素に最も近い既存のコンポーネントなど、デザイン パターンのリストが含まれています。
サポートすべき一般的なキーボード動作の 1 つに、上下左右の矢印キーがあります。この動作を新しいコンポーネントに追加するには、ロービング 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>
要素を使用して、モーダルの外側のクリックとタブをブロックしながら、ユーザー向けのモーダルを作成します。これにより、ユーザーは必須の選択に集中できます。