デジタル庁デザインシステム:Dialogモーダルのアクセシビリティ対応実装
あなたはWebアプリケーションでモーダルダイアログを実装する際、以下のような課題に直面したことはありませんか?
- スクリーンリーダー(Screen Reader)ユーザーがダイアログの存在に気づかない
- キーボード操作でダイアログ外にフォーカスが移動してしまう
- ESCキーで閉じる機能が実装されていない
- ダイアログの役割(role)やラベル付けが適切でない
これらの問題は、アクセシビリティ(Accessibility)対応が不十分なモーダル実装でよく見られる課題です。デジタル庁デザインシステムのDialogコンポーネントは、WCAG(Web Content Accessibility Guidelines)準拠を目指し、これらの課題を解決する実装パターンを提供しています。
目次
アクセシビリティ対応の重要性
Webアクセシビリティは、すべてのユーザーがWebコンテンツを利用できるようにするための設計原則です。特に行政サービスのデジタル化においては、アクセシビリティ対応は法的義務であり、社会的責任です。
Dialogコンポーネントの基本実装
デジタル庁デザインシステムのDialogコンポーネントは、HTML5の<dialog>要素をベースに、Reactで実装されています。
import { type ComponentProps, forwardRef } from 'react';
export type DialogProps = ComponentProps<'dialog'>;
export const Dialog = forwardRef<HTMLDialogElement, DialogProps>((props, ref) => {
const { children, className, ...rest } = props;
return (
<dialog
className={`bg-transparent p-6 backdrop:bg-black/45 ${className ?? ''}`}
onClick={(e) => {
e.currentTarget.close();
}}
ref={ref}
{...rest}
>
{children}
</dialog>
);
});
export type DialogBodyProps = ComponentProps<'div'>;
export const DialogBody = (props: DialogBodyProps) => {
const { children, className, ...rest } = props;
return (
<div
className={`flex flex-col items-center gap-4 rounded-12 border border-solid-gray-200 bg-white p-6 desktop:p-10 ${
className ?? ''
}`}
onClick={(e) => {
e.stopPropagation();
}}
{...rest}
>
{children}
</div>
);
};
キーボード操作の完全サポート
アクセシブルなダイアログは、マウスだけでなくキーボード操作も完全にサポートする必要があります。
必須のキーボード機能
| キー | 動作 | 重要性 |
|---|---|---|
| ESC | ダイアログを閉じる | 必須 |
| Tab | ダイアログ内の要素間を移動 | 必須 |
| Shift+Tab | 前の要素に移動 | 必須 |
| Enter | 主要アクションの実行 | 推奨 |
フォーカストラップの実装
ダイアログ表示中は、フォーカスがダイアログ外に移動しないようにする必要があります。
// フォーカストラップの実装例
useEffect(() => {
const handleTabKey = (e: KeyboardEvent) => {
if (e.key === 'Tab') {
const focusableElements = dialogRef.current?.querySelectorAll(
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
);
if (focusableElements && focusableElements.length > 0) {
const firstElement = focusableElements[0] as HTMLElement;
const lastElement = focusableElements[focusableElements.length - 1] as HTMLElement;
if (e.shiftKey && document.activeElement === firstElement) {
lastElement.focus();
e.preventDefault();
} else if (!e.shiftKey && document.activeElement === lastElement) {
firstElement.focus();
e.preventDefault();
}
}
}
};
document.addEventListener('keydown', handleTabKey);
return () => document.removeEventListener('keydown', handleTabKey);
}, []);
スクリーンリーダー対応の詳細
スクリーンリーダーユーザーにとって、ダイアログの存在と内容を正しく認識できることが重要です。
ARIA属性の適切な使用
<Dialog
aria-labelledby="dialog-heading"
aria-describedby="dialog-description"
role="dialog"
ref={dialogRef}
>
<DialogBody>
<h2 id="dialog-heading">ダイアログタイトル</h2>
<p id="dialog-description">ダイアログの説明文が入ります。</p>
{/* 操作ボタンなど */}
</DialogBody>
</Dialog>
アラートダイアログの特別対応
緊急性の高い通知にはrole="alertdialog"を使用します。
<Dialog
aria-labelledby="alert-heading"
ref={dialogRef}
role="alertdialog"
>
<DialogBody>
<h2 id="alert-heading">緊急通知</h2>
<p>重要なメッセージ内容が入ります。</p>
<Button onClick={() => dialogRef.current?.close()}>
了解
</Button>
</DialogBody>
</Dialog>
フォーカス管理のベストプラクティス
適切なフォーカス管理は、アクセシビリティの核心です。
フォーカス移動の戦略
実装コード例
const DialogExample = () => {
const dialogRef = useRef<HTMLDialogElement>(null);
const firstFocusableRef = useRef<HTMLButtonElement>(null);
const openDialog = () => {
dialogRef.current?.showModal();
// ダイアログ表示後に最初の要素にフォーカス
setTimeout(() => firstFocusableRef.current?.focus(), 100);
};
const closeDialog = () => {
dialogRef.current?.close();
};
return (
<div>
<Button onClick={openDialog}>ダイアログを開く</Button>
<Dialog ref={dialogRef} onClose={closeDialog}>
<DialogBody>
<h2 id="dialog-title">タイトル</h2>
<p>コンテンツ</p>
<Button ref={firstFocusableRef} onClick={closeDialog}>
閉じる
</Button>
</DialogBody>
</Dialog>
</div>
);
};
実装パターンとコード例
基本パターン
import { useRef } from 'react';
import { Button } from './Button';
import { Dialog, DialogBody } from './Dialog';
const BasicDialog = () => {
const dialogRef = useRef<HTMLDialogElement>(null);
return (
<div>
<Button onClick={() => dialogRef.current?.showModal()} size='lg' variant='solid-fill'>
ダイアログ表示
</Button>
<Dialog
aria-labelledby='dialog-heading'
className='max-w-[560px]'
ref={dialogRef}
>
<DialogBody>
<h2 className='text-std-24B-150' id='dialog-heading'>
ダイアログタイトル
</h2>
<p className='text-std-16N-170'>
ダイアログの補助テキストが入ります。
</p>
<div className='mt-6 flex gap-4'>
<Button onClick={() => dialogRef.current?.close()} size='lg'>
確定
</Button>
<Button onClick={() => dialogRef.current?.close()} variant='outline' size='lg'>
キャンセル
</Button>
</div>
</DialogBody>
</Dialog>
</div>
);
};
水平配置アクションパターン
const HorizontalActionsDialog = () => {
const dialogRef = useRef<HTMLDialogElement>(null);
return (
<Dialog
aria-labelledby='horizontal-dialog-heading'
className='max-w-[640px]'
ref={dialogRef}
>
<DialogBody>
<h2 id='horizontal-dialog-heading'>タイトル</h2>
<p>詳細な説明文</p>
<div className='flex flex-col gap-4 desktop:flex-row-reverse'>
<Button onClick={() => dialogRef.current?.close()} size='lg'>
主要アクション
</Button>
<Button onClick={() => dialogRef.current?.close()} variant='outline' size='lg'>
次要アクション
</Button>
<Button onClick={() => dialogRef.current?.close()} variant='text' size='lg'>
キャンセル
</Button>
</div>
</DialogBody>
</Dialog>
);
};
テストと検証方法
アクセシビリティ対応を確認するためのテスト方法を紹介します。
自動テストツール
| ツール | 用途 | 特徴 |
|---|---|---|
| Axe | 自動アクセシビリティテスト | CI/CDパイプライン統合可能 |
| Lighthouse | 総合的な品質評価 | Chrome DevTools統合 |
| WAVE | 視覚的なエラー表示 | ブラウザ拡張機能 |
手動テストチェックリスト
-
キーボード操作テスト
- Tabキーで全ての操作可能要素にアクセスできる
- Shift+Tabで逆方向移動が可能
- ESCキーでダイアログを閉じられる
-
スクリーンリーダーテスト
- ダイアログ表示時に適切なアナウンスがある
- タイトルと説明文が正しく読み上げられる
- 操作要素のラベルが適切
-
フォーカス管理テスト
- ダイアログ表示時にフォーカスが適切な要素に移動
- ダイアログ閉鎖時に元の要素にフォーカスが戻る
- フォーカスがダイアログ外に漏れない
-
視覚的テスト
- 十分なコントラスト比(4.5:1以上)
- フォーカスインジケータが明確に表示
- レスポンシブデザイン対応
Storybookでのテスト
デジタル庁デザインシステムはStorybookを採用しており、各コンポーネントのアクセシビリティを視覚的に確認できます。
npm run storybook
Storybookのアクセシビリティアドオンを使用することで、ARIA属性の状態やコントラスト比などをリアルタイムで確認できます。
まとめ
デジタル庁デザインシステムのDialogコンポーネントは、WCAGガイドラインに準拠したアクセシブルなモーダル実装を提供します。重要なポイントは:
- 適切なARIA属性でスクリーンリーダー対応
- 完全なキーボード操作サポート
- 堅牢なフォーカス管理によるユーザビリティ確保
- 視覚的明確性のためのデザイントークン活用
これらの実装パターンを活用することで、すべてのユーザーが利用しやすい行政デジタルサービスを構築できます。アクセシビリティは後付けではなく、設計段階から組み込むべき重要な要素です。
デジタル庁デザインシステムのコンポーネントは、継続的に改善されていくオープンソースプロジェクトです。実際の実装では、最新のバージョンとドキュメントを確認し、プロジェクトの要件に合わせて適切にカスタマイズしてください。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



