アクセシビリティ

すべてのピッカーコンポーネントは、組み込みのアクセシビリティサポートを備えています。キーボードナビゲーション、ARIA属性、フォーカス管理は、Styled、Tailwind v3/v4、Headlessのすべてのバリアントで、追加設定なしですぐに機能します。

標準的な使用では、追加の設定は必要ありません。このページでは、カスタムUIでパターンを監査、拡張、または複製できるように、含まれている機能について説明します。

キーボードナビゲーション

カレンダーピッカー

キーアクション
ArrowLeftフォーカスを前の日に移動
ArrowRightフォーカスを次の日に移動
ArrowUpフォーカスを前の週に移動(同じ曜日)
ArrowDownフォーカスを次の週に移動(同じ曜日)
Enter / Spaceフォーカスされている日を選択
Escape変更をキャンセルしてポップアップを閉じる
Tab次のフォーカス可能な要素に移動(ブラウザのデフォルト)

無効な日付のスキップ: 矢印キーでナビゲーションする際、無効な日付は自動的にスキップされます。ピッカーは、移動方向に最大365日間検索して、次の有効な日付を見つけます。

月の自動スクロール: キーボードフォーカスが別の月の日付に移動すると、カレンダービューはその月を表示するように更新されます。

タイムピッカー

キーアクション
Escape変更をキャンセルしてポップアップを閉じる

時刻の選択には、クリック/タッチ操作を伴うスクロールホイールUIを使用します。スクロールカラムは、正確な値を選択するために scroll-snap を使用します。

ARIA属性

すべてのインタラクティブな要素には、適切なARIAロールと属性があります:

ポップアップとコンテナ

要素属性
ポップアップコンテナrole"dialog"
インラインコンテナrole"group"
コンテナaria-labelロケールからのプレースホルダーテキスト
コンテナaria-activedescendant現在フォーカスされている日付セルのID

トリガーボタン

属性
aria-expandedポップアップが開いているときに true
aria-haspopup"dialog"

カレンダーグリッド

要素属性
グリッドラッパーrole"grid"
週の行role"row"
曜日のヘッダーセルrole"columnheader"
日付セルrole"gridcell"
日付セルaria-selected選択されているときに true
日付セルaria-currentセルが今日の場合に "date"
日付セルaria-labelフォーマットされた日付文字列(例: "2026-03-04"
日付セルdisabled無効な日付に設定(ネイティブHTML属性)

ナビゲーションとドロップダウン

要素属性
前の月のボタンaria-label「前の月」 (locale.prevMonthLabel から)
次の月のボタンaria-label「次の月」 (locale.nextMonthLabel から)
月のドロップダウンaria-label「月を選択」 (locale.selectMonthLabel から)
年のドロップダウンaria-label「年を選択」 (locale.selectYearLabel から)

時刻カラム

要素属性
時間カラムrole"listbox"
時間カラムaria-orientation"vertical"
時間カラムaria-label「時間」 (locale.hourLabel から)
分カラムrole"listbox"
分カラムaria-orientation"vertical"
分カラムaria-label「分」 (locale.minuteLabel から)
秒カラムrole"listbox"
秒カラムaria-orientation"vertical"
秒カラムaria-label「秒」 (locale.secondLabel から)
時刻アイテムrole「option」 (パディングアイテム: 「presentation」)
時刻アイテムaria-selectedアイテムが現在の値である場合に true
AM/PM切り替えaria-label現在の期間 + 「、AM/PMを切り替え」
クリアボタンaria-label「クリア」 (locale.clear から)

すべてのラベル文字列は、ロケールシステムを通じてカスタマイズ可能です。

フォーカス管理

Roving Tabindex

カレンダーグリッドは roving tabindex パターンを使用します:

  • 現在フォーカスされている日付セルのみが tabIndex={0} を持ちます(タブで移動可能)。
  • 他のすべての日付セルは tabIndex={-1} を持ちます(タブでは移動できませんが、矢印キーでフォーカス可能)。
  • これは、Tabキーがカレンダーグリッドからフォーカスを(次のコントロールへ)移動させ、矢印キーがグリッド内でフォーカスを移動させることを意味します。

ポップアップのフォーカストラップ

ポップアップモードは、@floating-ui/reactFloatingFocusManager を使用して、以下を実現します:

  • ポップアップが開いている間、フォーカスをその中にトラップします。
  • ポップアップが閉じられたときに、フォーカスをトリガーボタンに戻します。
  • ポップアップから背景コンテンツへのタブ移動を防ぎます。

ネイティブ要素

月と年の選択には、本質的にキーボードでアクセス可能なネイティブの <select> 要素を使用します。日付セルには、適切な無効状態を持つネイティブの <button> 要素を使用します。

WCAG 2.1準拠

以下のWCAG 2.1成功基準に対応しています:

基準レベル対応方法
1.3.1 情報及び関係性AセマンティックHTML — <button>, <select>, grid/gridcellロール
2.1.1 キーボードAすべての機能がキーボード(矢印キー、Enter、Escape)で到達可能
2.4.3 フォーカス順序A論理的なタブ順序。ポップアップはフォーカスマネージャーを使用
2.4.7 フォーカスの可視化AAすべてのインタラクティブな要素に :focus-visible のアウトライン(2pxの実線、プライマリーカラー)
4.1.2 名前、役割、値Aすべてのインタラクティブな要素は aria-label またはテキストコンテンツを介してアクセス可能な名前を持つ
📝 Note

スタイリングパッケージ(Styled, Tailwind v3/v4)には、デフォルトで可視のフォーカスインジケータが含まれています。headlessパッケージでカスタムUIを構築する場合は、独自のフォーカススタイルを提供する必要があります。

Headless: アクセシブルなカスタムUIの構築

headlessパッケージを直接使用している場合は、カスタムUIに以下が含まれていることを確認してください:

1. キーボードハンドラを適用する

矢印キーによるナビゲーションが機能するように、ポップアップコンテナに handleKeyDown を渡します:

const { handleKeyDown, ... } = useDatePicker({ value, onChange });
<div onKeyDown={handleKeyDown}>
{/* calendar grid */}
</div>

2. 日付セルに正しいtabIndexを設定する

getDayProps() からの isFocused フラグを使用します:

const dayProps = getDayProps(date);
<button
role="gridcell"
tabIndex={dayProps.isFocused ? 0 : -1}
aria-selected={dayProps.isSelected}
aria-current={dayProps.isToday ? "date" : undefined}
aria-label={locale.formatDate(date)}
>
{dayProps.day}
</button>;

3. グリッドにARIAロールを追加する

<div role="grid" aria-label={locale.placeholder}>
<div role="row">
{locale.weekdays.map((wd) => (
<div key={wd} role="columnheader">
{wd}
</div>
))}
</div>
{calendar.weeks.map((week, i) => (
<div key={i} role="row">
{/* day cells with role="gridcell" */}
</div>
))}
</div>

完全なウォークスルーについては、カスタムUIの構築を参照してください。