useId

useId でアクセシブルかつサーバー描画と整合する ID を作る方法を学ぶ。

useId は、アクセシビリティ属性を結び付けるための一意な ID を生成する Hook です。サーバー描画とクライアントの hydration でも同じ構造から整合した ID を作れます。

label と input を関連付ける

import { useId } from 'react';

function EmailField() {
  const id = useId();
  return <><label htmlFor={id}>メールアドレス</label><input id={id} type="email" /></>;
}

ページに EmailField を複数置いても、それぞれの呼び出しは別の ID を受け取ります。手で 'email' のような固定 ID を書くと label が意図しない input を指す可能性があるため、再利用可能なフォーム部品ほど useId が役立ちます。

同じコンポーネント内で複数の ID が必要なら、const hintId = ${id}-hint; のように共通の接頭辞から派生させます。aria-describedby と説明文の ID を結ぶ用途にも使えます。

label と input、エラーメッセージと aria-describedby のような関係が DOM 上で明示されると、スクリーンリーダー利用者が入力の目的と補足を把握できます。見た目だけ近くに置くより、属性で関係を表すことがアクセシビリティの基本です。

使わない場面

リストの key に useId を使ってはいけません。key はデータの同一性を表すため、データベース ID などデータ自身の安定した値を使います。また、各リスト要素で Hook を呼ぶ必要がある場合は、要素を子コンポーネントへ分けます。

複数の独立した React root を同じ HTML に描画する場合は、必要に応じて root ごとの identifierPrefix を設定します。これは ID 衝突を避けるためのアプリ基盤側の設定で、通常の単一 root の画面では意識する必要はありません。

ID をデータへ持ち出さない

useId の戻り値はコンポーネントのレンダー位置に基づく UI 用 ID です。保存した Todo の識別子、URL、テストデータの固定 selector として使うと、並び替えやレンダー構造の変更に弱くなります。データの identity とアクセシビリティ属性の ID は別の概念として扱います。

まとめ

useId は UI 部品の属性を安全に関連付ける ID のための Hook です。データ識別子や CSS セレクタの代用には使いません。

Sources