# Web アクセシビリティ実装ガイド【2026年版】— React / Next.js で WCAG 2.2 に準拠する実践テクニック

> React / Next.js で WCAG 2.2（AA）に準拠するアクセシビリティ実装の完全ガイド。セマンティック HTML、キーボード操作、フォーカス管理、ARIA の正しい使い方、フォーム、コントラスト、prefers-reduced-motion、WCAG 2.2 の新基準、axe による自動テストまで実コードで解説します。

- 公開日: 2026-06-24
- 著者: 友田 陽大
- タグ: React, Next.js, フロントエンド, アクセシビリティ, TypeScript, アーキテクチャ設計
- URL: https://tomodahinata.com/blog/react-nextjs-web-accessibility-wcag22-guide

## 要点

- アクセシビリティは障害者対応でなく全ユーザーの使いやすさであり、SEO とも強く相関する品質の総合点
- 狙う基準は WCAG 2.2 のレベル AA。2.2 で追加された9基準のうち6つが AA に影響する
- a11y の8割は正しいセマンティック HTML で解決する。ARIA は不足分を補う最後の手段（No ARIA is better than bad ARIA）
- キーボードで全操作に到達でき、:focus-visible でフォーカスを可視化し、モーダルはフォーカストラップと復帰を実装する
- テストは axe による自動検査（検出は3〜5割）と、キーボード・スクリーンリーダーの手動確認の二段構えで守る

---

アクセシビリティは「品質の総合点」が現れる場所です。雑なコンポーネント設計、状態管理の漏れ、フォーカスの放置——すべてが a11y の欠陥として表面化します。逆に言えば、a11y を担保できるチームは、コード品質そのものが高い。

---

## 1. なぜ今アクセシビリティなのか（ビジネスの観点）

技術論の前に、発注者にとっての価値を整理します。

- **対象ユーザーの拡大。** 何らかの支援を必要とする人は人口の相当割合に上ります。a11y はそのまま到達可能なユーザー数の拡大です。
- **法令・調達要件。** 公共・大企業の調達では WCAG 準拠が要件化されることが増えています。準拠していないと「そもそも候補に入れない」ことがあります。
- **SEO との相乗効果。** 適切な見出し構造、代替テキスト、セマンティックなマークアップは、検索エンジンとスクリーンリーダーの双方に効きます。a11y 改善は集客改善でもあります。
- **品質の証明。** アクセシブルなプロダクトは、設計が丁寧であることの証拠になります。発注判断の信頼材料になります。

つまり a11y は「コスト」ではなく「到達範囲・コンプライアンス・SEO・信頼」への投資です。

---

## 2. 土台：WCAG 2.2 の 4 原則（POUR）

WCAG はすべて 4 つの原則に集約されます。これを頭に入れておくと、個別テクニックが「なぜ必要か」で理解できます。

| 原則 | 意味 | 代表例 |
| ---- | ---- | ---- |
| Perceivable（知覚可能） | 情報が知覚できる | 画像の代替テキスト、十分なコントラスト |
| Operable（操作可能） | UI を操作できる | キーボード操作、十分なターゲットサイズ |
| Understandable（理解可能） | 内容と操作が理解できる | 一貫したナビ、明確なエラー |
| Robust（堅牢） | 支援技術が解釈できる | 妥当な HTML、適切な name/role/value |

レベルは A（最低限）< AA（標準）< AAA（最高）。**実務の目標は AA** です。

---

## 3. 最大のレバー：セマンティック HTML を使い切る

a11y の8割は、正しい要素を使うだけで達成できます。`div` と `span` でボタンやリンクを「作る」のをやめることが、最も費用対効果の高い改善です。

```tsx
// ❌ アンチパターン：div をボタンに見せかける
<div className="btn" onClick={handleClick}>送信</div>

// ✅ button は「フォーカス可能・Enter/Space で発火・支援技術がボタンと認識」を無料で得る
<button type="button" onClick={handleClick}>送信</button>
```

押さえどころ：

- **ページ遷移は `a`（Next.js は `Link`）、アクションは `button`。** 見た目で選ばず、意味で選ぶ。
- **見出しは階層を守る。** `h1` は1ページ1つ、`h2 → h3` を飛ばさない。スクリーンリーダー利用者は見出しでページを「拾い読み」します。
- **ランドマークで領域を示す。** `header` / `nav` / `main` / `footer` を使うと、支援技術がページ構造を提示できます。`main` は1つ。
- **リストは `ul`/`ol`、表は `table`＋`th`（`scope` 付き）。** 見た目だけ似せた `div` は構造情報を失います。

> セマンティック HTML は「後から ARIA で補う」より圧倒的に堅牢で、保守コストも低い。これは KISS そのものです。

---

## 4. キーボード操作とフォーカス管理

マウスを使えないユーザー（運動障害・スクリーンリーダー・パワーユーザー）にとって、キーボードだけで全機能に到達できることは生命線です。

### 4-1. すべての操作にキーボードで到達できるか

- Tab で論理的な順序に移動でき、Enter/Space/矢印で操作できること。
- **`tabindex` は `0`（フォーカス順に含める）か `-1`（プログラムでフォーカス可能）だけ。** 正の `tabindex` はフォーカス順を壊すので使わない。
- カスタムウィジェット（タブ、メニュー、コンボボックス）は [WAI-ARIA Authoring Practices](https://www.w3.org/WAI/ARIA/apg/) のキーボードパターンに従う。自作せず、Radix UI など検証済みのヘッドレス UI を使うのが安全で速い。

### 4-2. フォーカスは「見える」こと

```css
/* ❌ 絶対にやってはいけない：フォーカスリングを消すだけ */
:focus { outline: none; }

/* ✅ マウス利用時は控えめ、キーボード利用時ははっきり見せる */
:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}
```

### 4-3. ルート遷移・モーダルでのフォーカス移動

SPA／App Router ではページ遷移してもフォーカスが置き去りになりがちです。モーダルでは「開いたら中へフォーカス、閉じたら開いた要素へ戻す、背後を Tab で触れない（フォーカストラップ）」が必須です。

```tsx
function Dialog({ open, onClose, children }: DialogProps) {
  const ref = useRef<HTMLDivElement>(null);
  const opener = useRef<HTMLElement | null>(null);

  useEffect(() => {
    if (open) {
      opener.current = document.activeElement as HTMLElement;
      ref.current?.focus(); // 開いたら中へ
    } else {
      opener.current?.focus(); // 閉じたら開いた要素へ戻す
    }
  }, [open]);

  // Escape で閉じる、フォーカストラップ等は Radix Dialog 等に任せるのが堅実
  return open ? (
    <div role="dialog" aria-modal="true" tabIndex={-1} ref={ref}>
      {children}
    </div>
  ) : null;
}
```

実務では、こうした挙動を完備した Radix UI の `Dialog` を使うのが最短かつ安全です（このサイトの UI も Radix ベースです）。車輪の再発明は YAGNI 違反になりがちです。

---

## 5. ARIA は「最後の手段」— 正しい使い方

ARIA は HTML だけでは表現できない動的な情報（展開状態、ライブ更新など）を補う道具です。乱用は逆効果になります。

ARIA の5つの鉄則（公式の "Rules of ARIA" の要約）：

1. **ネイティブ HTML 要素があるなら、そちらを使う。** `role="button"` より `button`。
2. **ネイティブの意味を ARIA で上書きしない。** `<h2 role="tab">` のような破壊をしない。
3. **すべてのインタラクティブな ARIA はキーボードで操作可能に。**
4. **フォーカスできる要素を `role="presentation"` / `aria-hidden="true"` で隠さない。**（フォーカスできるのに支援技術から見えない、という矛盾を作らない）
5. **すべての操作要素にアクセシブルな名前を付ける。**

よく使う正しい例：

```tsx
// アイコンのみボタンには必ずラベルを
<button aria-label="メニューを開く" onClick={toggle}>
  <MenuIcon aria-hidden="true" />
</button>

// 開閉状態を伝える
<button aria-expanded={open} aria-controls="panel">詳細</button>
<div id="panel" hidden={!open}>...</div>

// 動的更新の通知（バリデーション結果やトースト）
<div role="status" aria-live="polite">{message}</div>
```

---

## 6. フォームのアクセシビリティ

フォームは a11y の失敗が最も多い場所です（詳細な実装は[React Hook Form × Zod 実践ガイド](/blog/react-hook-form)を参照）。最低限これだけは守ります。

- **すべての入力に `label`（`htmlFor` で関連付け）。** `placeholder` はラベルの代わりにならない（入力すると消え、コントラストも低い）。
- **エラーは `aria-invalid` と `aria-describedby` で入力欄に紐づけ、`role="alert"` で通知。**
- **必須は色だけに頼らない。** テキストや `*`＋凡例で示し、`aria-required` を付ける。
- **送信失敗時は最初のエラー項目へフォーカス。**

```tsx
<label htmlFor="email">メールアドレス</label>
<input
  id="email"
  type="email"
  aria-invalid={!!error}
  aria-describedby={error ? "email-error" : undefined}
/>
{error && <p id="email-error" role="alert">{error}</p>}
```

---

## 7. 色・コントラスト・モーション

### 色とコントラスト

- **本文テキストは背景とのコントラスト比 4.5:1 以上**（大きい文字は 3:1）。AA の必須基準です。
- **色だけで情報を伝えない。** 「赤＝エラー」はアイコンやテキストと併用する（色覚特性への配慮）。

### モーション（prefers-reduced-motion）

前庭障害のある人には、大きなアニメーションが体調不良を引き起こします。OS の「視差効果を減らす」設定を尊重します。**このサイトのアニメーション層も `prefers-reduced-motion` を尊重する設計**です。

```css
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
```

React 側でも判定できます。

```tsx
const reduced = useReducedMotion(); // motion ライブラリのフック等
<motion.div animate={reduced ? {} : { y: [20, 0], opacity: [0, 1] }} />
```

---

## 8. WCAG 2.2 の新基準（2026年に押さえるべき差分）

WCAG 2.2 で追加された 9 基準のうち、AA に影響する主要なものを実装観点で要約します。

| 基準 | レベル | 実装でやること |
| ---- | ------ | -------------- |
| 2.4.11 フォーカスの非遮蔽（最低限） | AA | 固定ヘッダーや Cookie バナーがフォーカス中の要素を完全に隠さない |
| 2.5.7 ドラッグ動作 | AA | ドラッグで行う操作に、クリック等の代替手段を用意する |
| 2.5.8 ターゲットサイズ（最低限） | AA | クリック対象は原則 24×24px 以上、または十分な間隔を確保 |
| 3.2.6 一貫したヘルプ | A | 問い合わせ等のヘルプ導線をページ間で同じ位置・順序に |
| 3.3.7 冗長な入力 | A | 同一手続き中で同じ情報を再入力させない（自動補完・引き継ぎ） |
| 3.3.8 アクセシブルな認証（最低限） | AA | パスワード記憶やパズルを必須にしない。パスワード貼り付け・パスキーを許可 |

特に **2.5.8 ターゲットサイズ** と **3.3.8 アクセシブルな認証** は、既存サイトが見落としがちです。小さなアイコンボタンの密集、貼り付け禁止のパスワード欄、CAPTCHA 必須のログインは、いずれも 2.2 で問題になります。

---

## 9. テスト戦略：自動 + 手動の二段構え

自動検査だけでは a11y 問題の3〜5割しか検出できません。**自動で土台を守り、手動で体験を確認する**のが正解です。

### 自動：axe を CI に組み込む

```ts
// tests/e2e/a11y.spec.ts （Playwright + @axe-core/playwright）
import { test, expect } from "@playwright/test";
import AxeBuilder from "@axe-core/playwright";

test("トップページに重大な a11y 違反がない", async ({ page }) => {
  await page.goto("/");
  const results = await new AxeBuilder({ page })
    .withTags(["wcag2a", "wcag2aa", "wcag22aa"])
    .analyze();
  expect(results.violations).toEqual([]);
});
```

開発中は `eslint-plugin-jsx-a11y` で静的に検出し、コンポーネント単位では `jest-axe` / `vitest-axe` を使うと、問題を早期に・安く潰せます（シフトレフト）。

### 手動：人にしか分からないこと

- **キーボードだけで全操作。** マウスを抜いて Tab・Enter・矢印・Escape で一周できるか。
- **スクリーンリーダー。** macOS の VoiceOver、Windows の NVDA で主要動線を聞く。
- **拡大表示。** 200% ズーム、400% 相当でレイアウトが破綻しないか。

---

## 10. アンチパターン（やりがちな失敗）

- ❌ `outline: none` でフォーカスリングを消す（キーボード利用者が迷子になる）。
- ❌ `div`/`span` に `onClick` だけ付けてボタン化（フォーカス・キーボード・役割がすべて欠落）。
- ❌ `placeholder` をラベル代わりに使う。
- ❌ 意味のない `role` や `aria-*` を盛る（「とりあえず ARIA」は害になる）。
- ❌ 画像 `alt` を空にすべき装飾画像と、内容のある画像を区別しない（装飾は `alt=""`、意味のある画像は説明を）。
- ❌ モーダルでフォーカストラップと復帰をしない。
- ❌ アニメーションで `prefers-reduced-motion` を無視する。

---

## 11. FAQ（よくある質問）

**Q. どのレベル（A/AA/AAA）を目標にすべき？**
A. 実務標準は AA です。多くの調達・ガイドラインが AA を基準にしています。AAA は一部基準のみ部分的に狙うのが現実的です。

**Q. axe（自動検査）に通れば WCAG 準拠と言える？**
A. 言えません。自動検査は機械的に判定できる範囲（3〜5割程度）のみです。キーボード操作やスクリーンリーダーでの体験は手動確認が必要です。

**Q. アクセシビリティ対応は SEO に効く？**
A. 効きます。見出し構造・代替テキスト・セマンティック HTML・明確なリンクテキストは、検索エンジンと支援技術の双方が読む情報源です。

**Q. 既存サイトの a11y 改善はどこから手を付ける？**
A. ①セマンティック HTML への置換、②キーボード操作とフォーカス可視化、③フォームのラベル・エラー、④コントラスト、の順が費用対効果が高いです。自動検査で現状把握してから優先度を付けます。

**Q. ヘッドレス UI（Radix 等）を使えば a11y は万全？**
A. 土台は大きく改善しますが万全ではありません。ラベル付与、コントラスト、コンテンツ構造、動線の一貫性はアプリ側の責任として残ります。

---

## まとめ：アクセシビリティは「品質の総合点」

アクセシビリティは特別な専門領域ではなく、**良い HTML・良い状態管理・良いフォーカス設計の積み重ね**です。だからこそ、a11y が担保されたプロダクトは総合的な品質が高い。

1. **セマンティック HTML** を使い切る（最大のレバー）。
2. **キーボード操作とフォーカス管理**を全動線で保証する。
3. **ARIA は補助**として正しく使う（誤用は無いほうがマシ）。
4. **フォーム・コントラスト・モーション**で誰も取りこぼさない。
5. **WCAG 2.2 の新基準**（ターゲットサイズ・アクセシブル認証など）を反映する。
6. **自動 + 手動テスト**で継続的に守る。

これらは到達ユーザー数の拡大、調達要件の充足、SEO 改善、そして「丁寧に作られている」という信頼に直結します。

**新規プロダクトのアクセシブルな設計、あるいは既存サイトの WCAG 2.2（AA）対応・改善が必要な場合は、お気軽にご相談ください。** 下記の事例では、現場の多様なユーザーが日々使う業務システムを、操作性と品質を両立して設計・実装した過程を紹介しています。
