トピックを検索
選択が読まれず、チップをキーボードで消せない複数選択
「スキル」欄は選んだスキルをチップで示しますが、チップの×はクリック処理を付けたsvgで、一覧のチェックマークもクラスで描いています。そのため、キーボードではチップを外せず、スクリーンリーダーにはどのスキルを選んだかが伝わりません。
<svg class="chip-remove" viewBox="0 0 16 16"> 問題
キーボード利用者は選んだスキルを外せず、スクリーンリーダーの利用者はどのスキルを選んだか分からないため、どちらも欄の内容を確かめたり直したりできません。
ある求人サイトのプロフィール入力フォームに、「スキル」欄があります。多くのUIライブラリーにある、複数選択のドロップダウンの形です。角の丸い一つの枠の中に、これまでに選んだデザインとリサーチがチップとして並び、それぞれに外すための小さな×が付いています。枠の端の山形の印を押すと、その下にスキルの一覧が開きます。マウスなら問題なく使えます。枠をクリックすれば一覧が開き、スキルをクリックすれば選べ、×をクリックすればチップが外れます。多くのライブラリーでは枠に文字を入力して一覧を絞り込めますが、ここではそれを省いています。入力による絞り込みは「候補を読み上げず、キーボードで選べないオートコンプリート」で扱っています。この欄は、よく次の二つのどちらかの作りになっています。
一つ目では、多くの複数選択のコンポーネントの初期設定と同じく、選んだスキルは一覧から消え、チップとしてだけ表示されます。Tabキーを押すと、二つのチップを飛ばして山形の印のボタンへ移り、Enterキーで一覧が開きます。矢印キーで強調が動き、Spaceキーで強調中のスキルを選べるので、スキルを足すことはできます。しかし、どちらの×にもフォーカスは当たらず、選んだスキルはもう一覧にありません。キーボードで操作する人が間違えてライティングを選ぶと、プロフィールから外す方法がありません。
二つ目では、すべてのスキルが一覧に残り、選んだものにチェックマークが付きます。今度はキーボードでも、一覧を開いてリサーチのチェックを外せます。スクリーンリーダーは「スキル、リストボックス」と読んだあと、強調が動くたびにスキルを読みます。ところが、チェックが付いているのがデザインとリサーチだとは伝わりません。一覧は複数選べることを示さず、どの選択肢も選択状態を持たないため、Chromiumのように、強調中のスキルを「選択」と伝えるブラウザーさえあります。ライティングでSpaceキーを押すと、画面にはチェックマークとチップが増えますが、何も読まれません。×は、この作りでもTabキーで飛ばされます。
達成基準2.1.1は、マウスでできることをキーボードでもできるよう求めています。どの×も、クリック処理を付けた svg です。svgは操作部品ではないためフォーカスを受け取れず、Tabキーはそこに止まらず、どのキーでも押せません。一つ目の作りでは、選んだスキルを外す方法は×だけなので、キーボードではスキルを足せても、外すことはできません。二つ目の作りでは、一覧でチェックを外すという別の方法がキーボードにもあるため、もう一つの問題がはっきり見えてきます。
達成基準4.1.2は、利用者が変えられる操作部品の状態を支援技術が取得できるよう求めています。スキルを選んでいるかどうかは、まさにその状態です。二つ目の作りでは、チェックマークはクラスをもとにCSSで描かれ、選択肢には aria-selected が、一覧には aria-multiselectable がありません。スクリーンリーダーが読む内容はブラウザーがマークアップから組み立てますが、クラスはブラウザーにとって意味を持たないため、伝えるべき選択状態も、複数選べる一覧であることも伝わりません。W3Cはこれを失敗例F15として挙げています。アクセシビリティAPIを不完全にしか使わないカスタムの操作部品で、ここでは役割はあっても状態がありません。
複数選択の欄には、スキル、興味のある分野、タグ、宛先など、プロフィールや絞り込みや投稿の中身を決めるものがよく入ります。取り消せない間違いや、確かめられない選択は、そのままフォームと一緒に送られます。
10グループ中2グループに影響
一般的なスキャンには、どちらの作りも問題なく見えます。山形の印は名前の付いたボタンで、リストボックスと選択肢の役割は正しく、役割のない svg は名前の要らない画像なので、スキャンのどの規則にも引っかかりません。その画像がクリックを受け付けることも、クラスがチェックマークを描いていることも、スキャンには見えません。EaseWebの診断は、チップの中にあってTabキーが届かない削除の×を、ew:chip-remove-unreachable として報告します。リストボックスの選択肢が aria-selected を持たず、クラスだけで選択済みに描かれていれば、ew:option-selection-not-exposed として報告します。aria-selected="true" の選択肢が二つ以上あるのに aria-multiselectable のないリストボックスは、確認が必要な項目として挙げます。AIに「チップを外せる複数選択」を頼むと、×をonClick付きのsvgやspanで書いたり、tabindex もキー操作もないまま role="button" だけを付けたり、チェックマークを selected クラスから描いたりすることがあります。使えるかどうかは、Tabキーで移動し、キーを押し、読み上げを聞いて初めて分かります。
試してみる
マウスを使わずに操作してください。Tabで「スキル」へ移動し、Enterで開き、矢印キーとSpaceでライティングを選び、Escapeで閉じてから、デザインを外します。
「スキル」は、選んだスキルをチップとして中に並べるドロップダウンです。問題1では、Tabはどの×にも止まらず、選んだスキルは一覧から消えるため、選んだものを取り消せません。×はクリックなら外せます。問題2では一覧でチェックを外し、下の欄を見てください。どのスキルにチェックが付いているか、一度でも読まれますか?修正後のチェックボックスでは、Tabでボックスの間を移動します。
問題あり 修正できますか?
- ライティング
- コーディング
- 動画編集
スクリーンリーダーの読み上げ:
(Tabで「スキル」へ移動)
修正方法
各チップにTabキーで届く削除ボタンを付け、各選択肢が選ばれているかどうかをコードで伝えます。
- 1チップの×は、Tabキーで届き、チップの名前を持つボタンにする。
- 2各選択肢が選ばれているかどうかは、チェックボックス、select、aria-selectedのいずれかでコードに示す。
- 3チップを外したら、フォーカスを次のチップか欄へ戻す。
マウスでしか外せない選んだスキル
<span id="skills-label">スキル</span><div class="skills-field"> <span class="chips"> <span class="chip"> デザイン <svg class="chip-remove" data-for="skill-design" viewBox="0 0 16 16">…</svg> </span> <span class="chip"> リサーチ <svg class="chip-remove" data-for="skill-research" viewBox="0 0 16 16">…</svg> </span> </span> <button type="button" class="skills-toggle" aria-labelledby="skills-label" aria-haspopup="listbox" aria-expanded="false" aria-controls="skills-list"> <span class="placeholder">スキルを追加</span> <svg class="chevron" viewBox="0 0 16 16" aria-hidden="true">…</svg> </button></div><ul id="skills-list" class="skills" role="listbox" tabindex="-1" aria-labelledby="skills-label" hidden> <li id="skill-design" role="option" hidden>デザイン</li> <li id="skill-writing" role="option">ライティング</li> <li id="skill-research" role="option" hidden>リサーチ</li> <li id="skill-coding" role="option">コーディング</li> <li id="skill-video" role="option">動画編集</li></ul>ドロップダウンの中のチェックボックスと、各チップのボタン
<span id="skills-label">スキル</span><div class="skills-field"> <span class="chips"> <span class="chip"> デザイン <button type="button" class="chip-remove" data-for="skill-design" aria-label="デザインを削除"> <svg viewBox="0 0 16 16" aria-hidden="true">…</svg> </button> </span> <span class="chip"> リサーチ <button type="button" class="chip-remove" data-for="skill-research" aria-label="リサーチを削除"> <svg viewBox="0 0 16 16" aria-hidden="true">…</svg> </button> </span> </span> <button type="button" class="skills-toggle" aria-labelledby="skills-label" aria-expanded="false" aria-controls="skills-list"> <span class="placeholder">スキルを追加</span> <svg class="chevron" viewBox="0 0 16 16" aria-hidden="true">…</svg> </button></div><div id="skills-list" class="skills" role="group" aria-labelledby="skills-label" hidden> <label class="skill"> デザイン <input type="checkbox" id="skill-design" name="skills" value="design" checked> </label> <label class="skill"> ライティング <input type="checkbox" id="skill-writing" name="skills" value="writing"> </label> <label class="skill"> リサーチ <input type="checkbox" id="skill-research" name="skills" value="research" checked> </label> <label class="skill"> コーディング <input type="checkbox" id="skill-coding" name="skills" value="coding"> </label> <label class="skill"> 動画編集 <input type="checkbox" id="skill-video" name="skills" value="video"> </label></div>この方法を選ぶ理由:まずHTMLの要素を使う
山形の印はボタンで、一覧はキーボードで操作できるため、スキルを足すことはできます。選んだスキルは一覧から消え、戻す方法はその×だけですが、×はフォーカスを受け取れない svg です。Tabキーは×を飛ばし、どのキーでもチップを外せません。
ドロップダウンの見た目はそのままで、中の一覧が本物のチェックボックスになります。各ボックスにはTabキーで移動でき、Spaceキーでチェックを付け外しできます。名前とチェックの有無も、ブラウザーがスクリーンリーダーに伝えます。「ライティング、チェックボックス、チェックなし」と読まれ、Spaceキーを押すと「チェック」と読まれます。山形の印のボタンで一覧が開き、フォーカスは最初のボックスへ移ります。Escapeキーで閉じるとフォーカスはボタンに戻り、フォーカスが外へ出たときや外側をクリックしたときも閉じます。グループの名前は「スキル」のラベルから付きます。各×は、svgを包む button になったので、Tabキーで届き、EnterキーかSpaceキーで押せます。ボタンの中身は画像だけで、そのままでは名前がないため、aria-label でどのチップを外すかを示します。チップを外すとボタンも一緒に消えるので、スクリプトでフォーカスを次のチップのボタンへ移します。次がなければ前のチップのボタンへ、チップが残っていなければ山形の印のボタンへ移します。これがないと、フォーカスのあったボタンが消え、フォーカスの行き場がなくなります。選んだスキルはチェック付きで一覧に残るため、どのスキルにも外す方法が二つあります。見た目は少し変わり、一覧の各行には、チェックを付けるまで空のボックスが表示されます。
三つとも2.1.1と4.1.2を満たし、どれにも同じチップのボタンが必要です。チェックボックスを使ってください。チェックボックスはどのブラウザーとスクリーンリーダーにも対応し、状態、キー操作、タッチ操作をスクリプトなしでブラウザーが用意します。チェックマークの一覧という見た目も保てます。ほぼすべての複数選択にチェックボックスを勧めるのは、このためです。ARIAのリストボックスを残すのは、一覧が長くTabキーの止まる場所を一つにまとめたい場合か、コンポーネントがすでにそう作られている場合です。そのときは、キー操作と状態の確認・保守を自分で引き受けてください。multiple付きの標準のselectは、短い一覧に限って使います。管理画面のように、使う人がそのキー操作を知っていて、ドロップダウンでなく開いた一覧でも構わない場合です。複数を選ぶ方法は横に書いてください。
各チップのボタンには、それぞれのフォーカスの枠と、押しやすい大きさが必要です。12ピクセルで描いた×でも、24×24ピクセルのボタンの中に置けます。名前は「削除」や「閉じる」ではなく「デザインを削除」とチップの名前を入れます。ボタンの一覧を前後の文脈なしで読み上げても、どのスキルを外すボタンかが分かるようにするためです。
チップを外したら、フォーカスは外したあとも残っている要素へ移す必要があります。上の方法では、次のチップのボタン、前のボタン、ドロップダウンの山形の印のボタン(標準のselectでは一覧)の順に移します。フォーカスを移しても、デザインが外れたことは伝わりません。スクリーンリーダーは次のボタンを読むだけです。外れたことを伝える必要があるなら、それは操作結果の確認の問題で、「バッジしか変わらない「カートに入れる」ボタン」で扱っています。
新しいタグを入力してEnterキーで追加するタグ入力欄では、空の欄でBackspaceキーを押すと最後のチップが消えることがよくあります。これはショートカットであり、ボタンの代わりにはなりません。並びの途中のチップは外せないからです。入力に合わせてタグの候補を出す欄なら、候補の作り方は「候補を読み上げず、キーボードで選べないオートコンプリート」を参照してください。「+3」のように件数でチップの並びを省略するなら、その件数を、隠れたチップを表示するボタンにしてください。そうしないと、隠れたチップにはまったく届きません。
チェックマークは背景の塗りではなく、currentColor の枠線かSVGで描きます。Windowsのコントラスト テーマでも残るようにするためです。強調中の選択肢にも、背景色に加えてアウトラインを付けます。content: "✓" のようにCSSの文字としてチェックマークを描くのも避けてください。生成された文字は、選択肢の名前の一部として読まれます。UIライブラリーはさまざまです。選んでいない選択肢の aria-selected を省くもの、×をspanで描くもの、選んだ選択肢を一覧から消すものがあります。ドキュメントではなく、出力されたマークアップを確認してください。値を一つだけ持つドロップダウンは「キーボードで開けず、読み上げられないカスタムのドロップダウン」で、一部の選択肢を選んだときの「すべて選択」のチェックボックスは mixed-checkbox のトピックで扱います。
AI コーディングアシスタントで修正しますか? このガイドを Markdown で取得、または全ガイドをコーディングエージェントで使う。
デザインの案
何を選んだかをコードが伝えていれば、選んだ値はどんな見た目でも構いません。
複数選択の見せ方としてよく見かけるものを、さらに5通り並べました。クリックしてから、マウスを使わずにTab、Space、Enterで試してください。3つは適合します。1つはTabが×に届かず、1つはピルを塗るだけで、選んだことをコードで伝えていません。
デザインファイルで
- 選択肢はチェックボックス、チップの×はボタンとデザインファイルに書き、本物の要素で作られるようにする。
- 各×ボタンの横に、「デザインを削除」のようにチップの言葉を入れた名前を書く。
- すべての×と選択肢を、Tabで到達したときのフォーカスの枠付きで描く。
- チップを外したあとのフォーカスの行き先を示す。次のチップか、残っていなければ欄。
- キーボードの利用者はホバーせず、タッチの利用者にはタップするまで出ないか、まったく出ないので、×はホバー時だけでなく常に表示する。
合格
- チェックマークが付くスキルのチップ すべてのスキルがピルで、ピル自体がチェックボックスです。オフは#6b7280の枠線(4.83:1)、オンは青緑の枠線と#ccfbf1の塗りに、言葉の前のチェックマークが付きます。文字は#115e59で、塗りに対して6.73:1です。外すための別のチップはなく、その場のピルでSpaceを押せば外れます。
- 件数と「すべて解除」付きのチェック一覧 チップは使いません。チェックボックスの上の行に選んだ件数を示し、横に「すべて解除」ボタンを置きます。件数はグループの中にあり、スクリーンリーダーは一覧と一緒に見つけられます。どのスキルも一覧のその場で外せるので、余分に移動する場所がありません。
- デザインライティング「+2件」ボタンで省略したチップ チップは2つだけ表示し、その後ろに残りを開く「+2件」ボタンを置きます。ボタンは開いているかどうかを伝えます。表示中のチップも開いたチップも、それぞれ×ボタンを持つので、届かないものはありません。
不合格
- デザイン ライティング リサーチ コーディングホバーで×が出るすっきりしたチップWCAG 2.1.1 何もしていないときのチップは言葉だけで、マウスを重ねると×が出ます。×はボタンではないためTabでは届かず、タッチ画面では、タップするまで×が出ないか、まったく出ません。Tabで試してください。
- 塗られるだけで何も伝えないピルWCAG 4.1.2 各ピルはボタンなのでTabとEnterで操作でき、選ぶと#0f766eに白い文字(5.47:1)で塗られます。しかし塗りはクラスから描かれ、スクリーンリーダーには、選んでいてもいなくても「ライティング、ボタン」としか聞こえません。
修正の確認
マウスを使わない5つの確認
確認方法: キーボード、スクリーンリーダー、強制配色
OS、ブラウザーと支援技術のバージョン、ビルド、実施日、各手順の実際の結果を記録してください。共通の複数選択のコンポーネントを変更した際は、再度確認します。
制限
これは、決まった選択肢の短い一覧のための出発点となる実装例です。グループ分けした選択肢、スクロールに合わせて読み込む選択肢、チップの並べ替えには当てはまりません。実際の選択肢を使い、対応するブラウザーと支援技術で操作全体を確認してください。
よくある問題を再現した学習用のサンプルです。実在のクライアントの診断結果ではありません。コードは出発点となる実装例のため、実際の製品でも確認してください。ここでは支援技術でのテスト結果は報告していません。
コードを更新しても、使いやすさを保つために
ガイドの内容を、コーディングエージェントやCIで使える開発ルールにまとめます。更新後は、キーボードとスクリーンリーダーで再テストし、問題が再発していないか確認します。