デジタル庁デザインシステム:LabelとLegendのフォーム関連付けベストプラクティス
はじめに
Webフォームのアクセシビリティ(アクセシビリティ)は、すべてのユーザーが平等に情報にアクセスできることを保証する重要な要素です。デジタル庁デザインシステム(DADS)では、LabelとLegendコンポーネントを通じて、フォーム要素の適切な関連付けを実現するためのベストプラクティスを提供しています。
この記事では、DADS v2のLabelとLegendコンポーネントを使用した効果的なフォーム関連付けの方法を、実践的なコード例とともに詳しく解説します。
LabelとLegendの基本的な違い
Labelコンポーネント
import { Label } from './components/Label';
// 単一のフォームコントロールに使用
<Label htmlFor="username">ユーザー名</Label>
<input id="username" type="text" />
Legendコンポーネント
import { Legend } from './components/Legend';
// フォームコントロールグループに使用
<fieldset>
<Legend>性別</Legend>
{/* ラジオボタンやチェックボックスのグループ */}
</fieldset>
アクセシビリティ対応の基本原則
1. 明示的な関連付け
// ✅ 推奨: htmlFor属性を使用した明示的関連付け
<Label htmlFor="email-input">メールアドレス</Label>
<input id="email-input" type="email" />
// ❌ 非推奨: 暗黙的関連付け(スクリーンリーダー対応が不完全)
<Label>
メールアドレス
<input type="email" />
</Label>
2. サイズ指定の適切な使用
// サイズバリエーション
<Label size="lg">大きなラベル</Label>
<Label size="md">標準ラベル</Label>
<Label size="sm">小さなラベル</Label>
実践的なフォーム関連付けパターン
単一入力フィールドの関連付け
import { Label, Input } from './components';
const EmailForm = () => (
<div className="space-y-2">
<Label htmlFor="email" size="lg">
メールアドレス
</Label>
<Input
id="email"
type="email"
placeholder="example@mail.com"
blockSize="lg"
/>
</div>
);
ラジオボタングループの関連付け
import { Legend, Radio } from './components';
const GenderSelection = () => (
<fieldset className="space-y-4">
<Legend size="md">性別</Legend>
<Radio name="gender" value="male" id="gender-male">
男性
</Radio>
<Radio name="gender" value="female" id="gender-female">
女性
</Radio>
<Radio name="gender" value="other" id="gender-other">
その他
</Radio>
</fieldset>
);
チェックボックスグループの関連付け
import { Legend, Checkbox } from './components';
const InterestsForm = () => (
<fieldset className="space-y-3">
<Legend>興味のある分野(複数選択可)</Legend>
<Checkbox name="interests" value="technology" id="interest-tech">
テクノロジー
</Checkbox>
<Checkbox name="interests" value="design" id="interest-design">
デザイン
</Checkbox>
<Checkbox name="interests" value="business" id="interest-business">
ビジネス
</Checkbox>
</fieldset>
);
複雑なフォームレイアウトのベストプラクティス
グリッドレイアウトでの使用
const ComplexForm = () => (
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{/* 姓 */}
<div>
<Label htmlFor="last-name" size="md">
姓
</Label>
<Input id="last-name" blockSize="md" />
</div>
{/* 名 */}
<div>
<Label htmlFor="first-name" size="md">
名
</Label>
<Input id="first-name" blockSize="md" />
</div>
{/* フルセットのフィールドセット */}
<div className="md:col-span-2">
<fieldset>
<Legend size="lg">連絡先情報</Legend>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mt-4">
{/* 各入力フィールド */}
</div>
</fieldset>
</div>
</div>
);
エラー状態の対応
エラー時の関連付け
const FormWithValidation = () => {
const [error, setError] = useState(false);
return (
<div className="space-y-2">
<Label htmlFor="username" className={error ? 'text-error-1' : ''}>
ユーザー名 {error && '(必須)'}
</Label>
<Input
id="username"
isError={error}
onBlur={(e) => setError(!e.target.value)}
/>
</div>
);
};
アクセシビリティ考慮事項
スクリーンリーダー最適化
キーボードナビゲーション
// 適切な関連付けによりTabキーでのナビゲーションが可能
const AccessibleForm = () => (
<form>
<Label htmlFor="name">名前</Label>
<Input id="name" />
<Label htmlFor="email">メール</Label>
<Input id="email" />
<fieldset>
<Legend>オプション</Legend>
<Radio name="option" value="1" id="option1">オプション1</Radio>
<Radio name="option" value="2" id="option2">オプション2</Radio>
</fieldset>
</form>
);
パフォーマンス最適化
メモ化による再レンダリング防止
import { memo } from 'react';
const MemoizedLabel = memo(({ htmlFor, children, size = 'md' }) => (
<Label htmlFor={htmlFor} size={size}>
{children}
</Label>
));
// 使用例
<MemoizedLabel htmlFor="optimized-input" size="lg">
最適化されたラベル
</MemoizedLabel>
テスト戦略
ユニットテストの例
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { Label, Input } from './components';
test('LabelがInputと正しく関連付けられている', async () => {
render(
<>
<Label htmlFor="test-input">テストラベル</Label>
<Input id="test-input" />
</>
);
const input = screen.getByLabelText('テストラベル');
await userEvent.type(input, 'テスト値');
expect(input).toHaveValue('テスト値');
});
よくある間違いと解決策
間違ったパターン
// ❌ IDの重複
<Label htmlFor="same-id">ラベル1</Label>
<input id="same-id" />
<Label htmlFor="same-id">ラベル2</Label> {/* 同じIDは使用不可 */}
<input id="same-id" />
// ❌ 不適切なfieldsetのネスト
<fieldset>
<Legend>外側</Legend>
<fieldset> {/* ネストされたfieldsetは避ける */}
<Legend>内側</Legend>
</fieldset>
</fieldset>
正しいパターン
// ✅ 一意のIDを使用
<Label htmlFor="unique-id-1">ラベル1</Label>
<input id="unique-id-1" />
<Label htmlFor="unique-id-2">ラベル2</Label>
<input id="unique-id-2" />
// ✅ 複数のfieldsetは並列に配置
<fieldset>
<Legend>セクション1</Legend>
{/* コンテンツ */}
</fieldset>
<fieldset>
<Legend>セクション2</Legend>
{/* コンテンツ */}
</fieldset>
まとめ
デジタル庁デザインシステムのLabelとLegendコンポーネントを適切に使用することで、以下のメリットを得られます:
- アクセシビリティの向上: スクリーンリーダーユーザーを含むすべてのユーザーがフォームを利用可能
- ユーザビリティの改善: 明確なラベル付けによりフォームの理解が容易
- コードの保守性: 一貫したパターンにより開発効率が向上
- コンプライアンス対応: WCAGガイドラインに準拠した実装
適切なフォーム関連付けは、単なる技術的要件ではなく、包括的なユーザー体験を提供するための重要な要素です。DADSのコンポーネントを活用して、よりアクセシブルで使いやすいフォームを実現しましょう。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



