アクセシブルなフォーム(2023/11/02の朝までマークアップより)

ラベルの無い検索フィールド

label要素の代わりにaria-label属性でラベル付けをする

2023年新しく追加されたHTML要素のsearch要素を使う。
ただしブラウザの対応が十分ではないため、フォールバックとしてrole="search"も併用する。

<search role="search">

  <form action="#">

    <input type="search" name="q" aria-label="検索">

    <button>検索</button>

  </form>

</search>

グループになったフォームコントロール

fieldsetとlegendを使ってマークアップする。
fieldset要素の暗黙のroleはgroupだが、ラジオボタンの場合は role="radiogroup" でroleをオーバーライドできる。

横並びにしたい場合:fieldset要素に display:flex;や display:grid;は使えないので、fieldsetの外側をdivで囲み、fieldsetを display:contents;にして横並びにする

<div>

  <fieldset role="radiogroup">

    <legend>HTMLは好きですか?</legend>

    <input type="radio" name="html" id="yes">

    <label for="yes">はい</label>

    <input type="radio" name="html" id="no">

    <label for="no">いいえ</label>

  </fieldset>

</div>

なんとかかんとかですか?

入力のヒント

aria-describedby属性を使用して入力フィールドにヒントテキストを関連付ける

<div>

  <label for="tel">電話番号</label>

  <p id="tel-hint">日中に連絡可能な電話番号をご入力ください</p>

   <input type="text" name="tel" id="tel" aria-describedby="tel-hint">

</div>

日中に連絡可能な電話番号をご入力ください

エラー

1) aria-invalid属性を使用して、マシンリーダブルなエラー状態を作る
2) aria-describedby属性を使用して入力フィールドにエラーメッセージを関連付ける

(aria-errormessage属性という、aria-describedby属性の代わりとして使用できるエラーメッセージを関連付けるためのWAI-ARIAもあるが、2023年現在一部のスクリーンリーダーでしか対応しておらず、時期尚早)

エラーの通知【エラー検証項目がページに1つの場合】

role="alert"(aria-live="assertive")を使用する。role="alert"の領域は監視領域となり、変更を感知するとスクリーンリーダーは現在の読み上げを中断し、即時アナウンスする。
その機能を利用して、role="alert"の領域を先に用意しておき(中身は空)、送信ボタン押下時にエラーが合ったときにpタグでエラー文を挿入する。

[注意1] 送信ボタンを押下時に検証するonSubmitErrorの場合、role="alert" が付与された複数のエラーメッセージを同時に出すと最後のエラーしか読み上げない
[注意2] フォーカスを外した際に検証するonBlurErrorの場合、次の入力項目に フォーカスを移した途端に前のエラーが読み上げられることになり、今フォーカスしている項目が聞こえなくなる

<div>

  <label for="email">メールアドレス</label>

  <div role="alert">

    <p id="email-error">メールアドレスを入力してください</p>

  </div>

  <input type="email" name="email" id="email" aria-invalid="true" aria-describedby="email-error">

</div>

メールアドレスを入力して下さい。

エラーの通知【エラー検証項目がページに複数の場合】

role="status"(aria-live="polite")を使用するか、ライブリージョンを使用せずエラーサマリー(エラーをまとめたUI)を表示してサマリーにキーボードフォーカスを移す。
下の例では role="status" を使用している。

<div>

  <label for="name">メールアドレス</label>

  <div role="status">

    <p id="name-error">メールアドレスを入力してください</p>

  </div>

  <input type="text" name="name" id="name" aria-invalid="true" aria-describedby="name-error">

</div>

<div>

  <label for="email">メールアドレス</label>

  <div role="status">

    <p id="email-error">メールアドレスを入力してください</p>

  </div>

  <input type="email" name="email" id="email" aria-invalid="true" aria-describedby="email-error">

</div>

お名前を入力して下さい。

メールアドレスを入力して下さい。