Skip to content

ARIA 属性

19.2.1. 基本 ARIA 属性

ARIA (Accessible Rich Internet Applications) 属性は、ネイティブ HTML 要素だけでは意味を伝達できない場合に使用します。ネイティブ HTML のセマンティクスで十分な場合は ARIA 属性を追加しません。

属性用途使用規則
role要素の役割定義ネイティブ HTML 要素の暗黙的な役割と重複しないように使用
aria-label要素のアクセシブルな名前の指定視覚的なラベルがない要素に使用
aria-labelledby他の要素のテキストで名前を指定視覚的なラベルがある場合、該当要素の id を参照
aria-describedby要素に対する追加説明の関連付けヘルプテキスト、ヒントテキストなどを関連付ける際に使用
vue
<template>
  <!-- aria-label: 視覚的テキストがないアイコンボタン -->
  <button aria-label="検索" @click="handleSearch">
    <SearchIcon />
  </button>

  <!-- aria-labelledby: 視覚的ラベルを参照 -->
  <h2 id="section-title">ユーザー一覧</h2>
  <table aria-labelledby="section-title">
    <!-- テーブル内容 -->
  </table>

  <!-- aria-describedby: 追加説明の関連付け -->
  <input
    id="password"
    type="password"
    aria-describedby="password-hint"
  />
  <p id="password-hint">8文字以上、英字と数字を含めなければなりません。</p>
</template>
  • <button><nav><header> などのネイティブセマンティック要素に同一の意味の role を重複して指定しません。
  • aria-labelaria-labelledby を同時に使用しません。aria-labelledby が優先されます。

19.2.2. ライブリージョン

動的に変更されるコンテンツを支援技術に通知するためにライブリージョンを使用します。

属性動作
aria-livepoliteユーザーの現在の操作が終了した後に変更内容を通知
aria-liveassertive即座に変更内容を通知。緊急の通知にのみ使用
aria-atomictrue / falseリージョン全体を再読み上げするか、変更部分のみ読み上げるかを決定
vue
<script setup lang="ts">
import { ref } from 'vue'

const statusMessage = ref('')
const errorMessage = ref('')

async function handleSave() {
  try {
    await saveData()
    statusMessage.value = '保存が完了しました。'
  } catch {
    errorMessage.value = '保存に失敗しました。もう一度お試しください。'
  }
}
</script>

<template>
  <!-- polite: 一般的なステータスメッセージ -->
  <div aria-live="polite" aria-atomic="true">
    {{ statusMessage }}
  </div>

  <!-- assertive: 緊急エラーメッセージ -->
  <div aria-live="assertive" aria-atomic="true" role="alert">
    {{ errorMessage }}
  </div>
</template>
  • aria-live="assertive"エラー通知、セッション期限切れ警告 など緊急の場合にのみ使用します。
  • 一般的なステータス更新(ロード完了、データ更新など)には aria-live="polite" を使用します。
  • ライブリージョン要素は ページロード時点で DOM に存在 していなければなりません。動的に生成すると支援技術が認識できません。

19.2.3. モーダル/ダイアログ

モーダルダイアログは以下の ARIA 属性とフォーカス管理規則を遵守しなければなりません。

vue
<script setup lang="ts">
import { ref, nextTick } from 'vue'

const isOpen = ref(false)
const dialogRef = ref<HTMLElement | null>(null)
let previousFocus: HTMLElement | null = null

async function openModal() {
  previousFocus = document.activeElement as HTMLElement
  isOpen.value = true
  await nextTick()
  dialogRef.value?.focus()
}

function closeModal() {
  isOpen.value = false
  previousFocus?.focus()
}
</script>

<template>
  <div
    v-if="isOpen"
    ref="dialogRef"
    role="dialog"
    aria-modal="true"
    aria-labelledby="dialog-title"
    tabindex="-1"
  >
    <h2 id="dialog-title">確認</h2>
    <p>変更内容を保存しますか?</p>
    <button @click="closeModal">キャンセル</button>
    <button @click="handleConfirm">保存</button>
  </div>
</template>
  • role="dialog"aria-modal="true" を必ず指定しなければなりません。
  • aria-labelledby でダイアログのタイトル要素を参照しなければなりません。
  • モーダルが開いたら モーダル内部の最初のフォーカス可能な要素 またはダイアログ自体にフォーカスを移動しなければなりません。
  • モーダルが閉じたら モーダルを開く前の要素 にフォーカスを復元しなければなりません。
  • モーダルが開いた状態でフォーカスがモーダル外部に移動しないよう フォーカストラッピング を実装しなければなりません。

19.2.4. フォームアクセシビリティ

フォーム要素は以下の ARIA 属性を使用してアクセシビリティを保証しなければなりません。

属性用途適用対象
aria-required必須入力フィールドの表示必須入力フィールド
aria-invalidバリデーション失敗状態の表示バリデーションに失敗したフィールド
aria-errormessageエラーメッセージ要素の関連付けaria-invalid="true" のフィールド
vue
<template>
  <form @submit.prevent="handleSubmit">
    <label for="user-email">メールアドレス</label>
    <input
      id="user-email"
      v-model="form.email"
      type="email"
      aria-required="true"
      :aria-invalid="!!errors.email"
      :aria-errormessage="errors.email ? 'email-error' : undefined"
      @blur="validateField('email')"
    />
    <p
      v-if="errors.email"
      id="email-error"
      role="alert"
    >
      {{ errors.email }}
    </p>
  </form>
</template>
  • すべての入力フィールドには <label> 要素を関連付けなければなりません。<label>for 属性と <input>id 属性を一致させます。
  • placeholder をラベルの代用として使用しません。placeholder は補助的なヒントテキストとしてのみ使用します。
  • aria-invalid はバリデーションが実行された後にのみ true に設定します。初期状態では設定しません。
  • aria-errormessagearia-invalid="true" の場合にのみ参照先が有効でなければなりません。

TIENIPIA QUALIFIED STANDARD