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-labelとaria-labelledbyを同時に使用しません。aria-labelledbyが優先されます。
19.2.2. ライブリージョン
動的に変更されるコンテンツを支援技術に通知するためにライブリージョンを使用します。
| 属性 | 値 | 動作 |
|---|---|---|
aria-live | polite | ユーザーの現在の操作が終了した後に変更内容を通知 |
aria-live | assertive | 即座に変更内容を通知。緊急の通知にのみ使用 |
aria-atomic | true / 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-errormessageはaria-invalid="true"の場合にのみ参照先が有効でなければなりません。