開閉状態が伝わらないアコーディオン
見出しをクリックすると内容が開きますが、ボタンであることや開閉状態が支援技術に伝わりません。
問題
どの見出しが開閉でき、今開いているのかが、キーボードやスクリーンリーダーでは分かりません。
場面 クリックでは開くが、キー操作では開かない。 詳しく読む閉じる
FAQの見出しをクリックすると回答が開きますが、支援技術には普通のテキストとして伝わります。キーボードでは開閉できません。
確認できる問題 見出しが操作部品として振る舞い、状態を持たない。 詳しく読む閉じる
見出しが開閉の操作を受け付けるのに、ボタンの役割が設定されていません。開閉状態も伝わらず、閉じたパネル内のリンクにTabキーで移動できてしまう場合があります。
利用者への影響 キーボード利用者と、開閉状態を聞き取る人。 詳しく読む閉じる
どの見出しが操作可能か、開いているかがわかりません。非表示の要素にフォーカスが移ると、操作している場所が分からなくなります。
自動チェックとAIの限界 属性があっても、状態が常に一致するかは確認されない。 詳しく読む閉じる
属性不足は検出できても、すべての状態遷移で aria-expanded が一致し、非表示の子要素にフォーカスが入らないことまでは証明できません。開閉を繰り返して確認してください。
試してみる
TabとEnterで、回答を開いてください。
Tabキーで質問へ移動して開いてください。閉じた状態でTabを押し続けると、フォーカスは消えますか?
修正方法
detailsとsummaryを使うか、見出し内のbuttonで開閉状態を伝えます。
- 1
aria-expandedを、実際の表示と常に一致させる。 - 2閉じたパネルは高さ0ではなく、
hidden属性で隠す。 - 3ページの構造に合った見出しレベルを保つ。
<h3 class="faq-q" onclick="toggle(this)">返金の流れは?</h3><div class="faq-a" style="height: 0; overflow: hidden"> <p>返金は5日以内に届きます。<a href="/refunds">返金ポリシー</a></p></div><details> <summary>返金の流れは?</summary> <p>返金は5日以内に届きます。<a href="/refunds">返金ポリシー</a></p></details>html
<h3> <button type="button" aria-expanded="false" aria-controls="faq-refunds"> 返金の流れは? </button></h3><div id="faq-refunds" hidden> <p>返金は5日以内に届きます。<a href="/refunds">返金ポリシー</a></p></div>js
for (const button of document.querySelectorAll('[aria-controls]')) { button.addEventListener('click', () => { const open = button.getAttribute('aria-expanded') === 'true'; button.setAttribute('aria-expanded', String(!open)); document.getElementById(button.getAttribute('aria-controls')).hidden = open; });}この修正で直る理由
見出しにはTabキーで移動できず、開閉状態も伝わりません。閉じたパネルは高さを0にしているだけなので、中のリンクが見えないままフォーカスを受け取ります。
単純な質問と回答なら、details と summary を使うと、スクリプトなしでキーボード操作、開閉状態の伝達、閉じた内容のTab順からの除外ができます。
デザイン上、細かな制御が必要な場合は、見出しの中にbutton要素を置き、その状態とパネルの表示を一致させます。
hidden 属性を付けると、閉じたパネルはTab順からも、スクリーンリーダーが読む範囲からも外れます。アニメーションを付ける場合も、高さを0にするだけでなく、最後に hidden が設定されるようにしてください。
実装の判断
見出しとアイコンは、一つの開閉ボタンにまとめます。detailsとsummaryを使う場合、通常は aria-expanded を追加する必要はありません。独自実装では、固定のIDと aria-controls でボタンとパネルを関連付け、複数のパネルを同時に開けるかを決めます。矢印キーへの対応は任意ですが、Tabキーで移動できることは必須です。
見出しレベルはページ全体の構造に合わせ、スクリーンリーダーの見出し移動でも質問として使えるようにします。
修正の確認
マウスを使わない5つの確認
OS、ブラウザーと支援技術のバージョン、ビルド、実施日、各手順の実際の結果を記録してください。共通のアコーディオンコンポーネントを変更した際は、再度確認します。
制限
このサンプルは、どのアプリケーションでも同じ結果になることを保証するものではありません。スクリプトは、アニメーションやリンクでの直接表示を含まない最小限の例です。実際に使用する支援技術で、操作全体を確認してください。
よくある問題を再現した学習用のサンプルです。実在のクライアントの診断結果ではありません。コードは出発点となる実装例のため、実際の製品でも確認してください。ここでは支援技術でのテスト結果は報告していません。
参考資料: www.w3.org
コードを更新しても、使いやすさを保つために
ガイドの内容を、コーディングエージェントやCIで使える開発ルールにまとめます。更新後は、キーボードとスクリーンリーダーで再テストし、問題が再発していないか確認します。