実践Webアクセシビリティ

アクセシブルなカスタムUIコントロールの実装:ARIA属性、キーボード操作、状態管理

Tags: カスタムコントロール, ARIA属性, キーボード操作, JavaScript, アクセシビリティ, UI実装

はじめに

ウェブサイトやアプリケーションの開発において、標準のHTML要素だけでは表現できない複雑なUIコンポーネントが必要になることがあります。このような場合、JavaScriptなどを使用して独自のUIコントロール(カスタムコントロールやカスタムウィジェットとも呼ばれます)を実装することがあります。しかし、<div><span>などの意味を持たない要素でUIを構築し、スタイルやJavaScriptで機能を追加するだけでは、そのコントロールが持つ役割や状態、プロパティといった重要な情報が失われてしまいます。

これにより、キーボードユーザーやスクリーンリーダーユーザーなど、支援技術を利用するユーザーはそのコントロールが何であるか、現在どのような状態にあるのかを認識できず、操作が困難または不可能になってしまいます。例えば、スタイルでチェックボックスのように見せかけただけの<div>は、スクリーンリーダーからは単なるテキスト領域としてしか認識されません。

本記事では、このようなカスタムUIコントロールをアクセシブルにするための具体的な実装方法について、ARIA属性、キーボード操作、そして状態管理に焦点を当てて解説します。

なぜカスタムUIコントロールのアクセシビリティ対応が必要か

標準のHTML要素(<button>, <input type="checkbox">, <select>, <option>など)は、ブラウザによってデフォルトでアクセシブルな情報と操作性が提供されています。例えば、<button>はスクリーンリーダーに「ボタン」であることを伝え、EnterキーやSpaceキーでのアクティベーションをサポートしています。

一方、<div><span>といったセマンティクスを持たない要素で同じ見た目と機能を持つUIをJavaScriptで実装した場合、これらのデフォルトのアクセシビリティ特性は失われます。支援技術はこれらの要素を単なる汎用要素としてしか認識せず、その本来の役割や状態、操作方法をユーザーに適切に伝えることができません。

カスタムUIコントロールをアクセシブルに対応することは、以下のために不可欠です。

アクセシビリティ対応のための基本的なアプローチ

カスタムUIコントロールをアクセシブルにするためには、主に以下の要素を実装する必要があります。

  1. セマンティクス(役割)の付与: その要素がどのような種類のUIコントロールであるかを支援技術に伝えます。これは主にARIA role属性を使用します。
  2. 状態(State)とプロパティ(Property)の伝達: コントロールの現在の状態(例: 選択されている、無効)やプロパティ(例: スライダーの現在値)を支援技術に伝えます。これは主にARIA aria-* 属性(aria-checked, aria-disabled, aria-valuenowなど)を使用します。
  3. キーボード操作への対応: 標準的なキーボードでの操作(Tabでのフォーカス移動、Space/Enterでのアクティベーション、矢印キーでの値変更など)をJavaScriptで実装します。
  4. フォーカス管理: コントロールがフォーカス可能であり、フォーカスインジケーターが表示されるようにします。tabindex属性やCSSを使用します。

具体的な実装手順とコード例

ここでは、簡単なカスタムトグルボタン(カスタムチェックボックスやスイッチのようなもの)を例に、上記のアプローチをどのように適用するかを解説します。

例:アクセシブルなカスタムトグルボタン

この例では、<div>要素を使って、クリックやキーボード操作でオン/オフが切り替わるトグルボタンを作成します。

1. HTML マークアップ

まず、ベースとなるHTML要素を用意します。この要素に、その役割と初期状態、フォーカス可能性を付与します。

<div
  role="switch"
  aria-checked="false"
  tabindex="0"
  id="customToggle"
>
  アラート通知を受け取る
</div>

2. CSS スタイリング

見た目を整え、状態に応じたスタイル(オン/オフなど)やフォーカスインジケーターを追加します。特に、フォーカスインジケーターはキーボードユーザーにとって非常に重要です。

[role="switch"] {
  display: inline-block;
  padding: 8px 12px;
  border: 1px solid #ccc;
  border-radius: 4px;
  cursor: pointer;
  background-color: #f0f0f0;
  margin: 4px; /* 見た目の調整 */
}

/* オン状態のスタイル */
[role="switch"][aria-checked="true"] {
  background-color: #4CAF50; /* 緑色など */
  color: white;
  border-color: #4CAF50;
}

/* フォーカスインジケーター */
[role="switch"]:focus {
  outline: 2px solid blue; /* 標準のoutlineでも良いが、カスタマイズも可能 */
  outline-offset: 2px;
}

3. JavaScript による機能と状態管理

クリックおよびキーボードイベント(Space/Enterキー)に対するイベントハンドラを設定し、状態(aria-checked属性の値)を更新します。状態が変更されたら、その変更がDOMに反映されるようにします。

const customToggle = document.getElementById('customToggle');

if (customToggle) {
  customToggle.addEventListener('click', toggleSwitch);
  customToggle.addEventListener('keydown', handleKeyPress);
}

function toggleSwitch() {
  const isChecked = customToggle.getAttribute('aria-checked') === 'true';
  // 状態を反転させてaria-checked属性を更新
  customToggle.setAttribute('aria-checked', String(!isChecked));

  // 必要に応じて、UIの見た目を更新するCSSクラスを付与するなど
  // customToggle.classList.toggle('is-checked', !isChecked);
}

function handleKeyPress(event) {
  // SpaceキーまたはEnterキーが押されたらトグル関数を呼び出す
  if (event.key === ' ' || event.key === 'Enter') {
    event.preventDefault(); // 標準のキーイベントによるスクロールなどを防ぐ
    toggleSwitch();
  }
}

このJavaScriptコードでは、以下の重要な処理を行っています。

その他のカスタムコントロールの例

実装時の注意点

テスト方法

カスタムUIコントロールの実装後、アクセシビリティ対応が適切に行われているかを確認するために、以下の方法でテストを実施してください。

  1. キーボード操作のみでのテスト: マウスを使わずに、Tabキー、Shift+Tabキー、Spaceキー、Enterキー、およびそのコントロールに必要なその他のキー(矢印キーなど)ですべての操作ができるかを確認します。フォーカスが適切に移動し、フォーカスインジケーターが表示されるかを確認します。
  2. スクリーンリーダーでのテスト: NVDA (Windows), VoiceOver (macOS/iOS), JAWS (Windows), TalkBack (Android) などのスクリーンリーダーを使用して、コントロールの役割、名前、状態、プロパティが正しく読み上げられるかを確認します。操作した際に状態の変化が適切に伝えられるかも重要です。
  3. アクセシビリティ評価ツールの利用: Lighthouse, Axe DevTools, WAVEなどの自動評価ツールを実行し、基本的なARIA属性の不足やエラーがないかを確認します。ただし、これらのツールは機械的なチェックのみを行うため、手動でのテスト(特にキーボードとスクリーンリーダー)は必須です。

まとめ

カスタムUIコントロールをアクセシブルに対応させることは、多くのユーザーにとってウェブサイトやアプリケーションの利用可能性を大きく左右します。role属性による役割の明示、aria-*属性による状態やプロパティの伝達、そしてJavaScriptによる包括的なキーボード操作への対応は、カスタムコントロールをアクセシブルにするための基本的なステップです。可能な限りネイティブ要素の利用を検討しつつ、カスタム実装が必要な場合には、本記事で紹介したアプローチとコード例を参考に、すべてのユーザーが利用できるUIを目指してください。