Skip to content
fandhe-frontendcore v0.4.3
GitHub

Calendar

月表示と単一日付の選択を、WAI-ARIA の grid パターンに従った 11 個の anatomy パーツ(Root/Heading/PrevTrigger/NextTrigger/Table/…/DayTrigger)として提供する unstyled 部品です。「今日」は呼び出し側が明示的に渡す引数であり、内部で時刻取得 API を使わない決定的な設計です。矢印キー等でのキーボード操作は fandhe-frontend-wasm-full が配線します。

Themes 版(fandhe-frontend-pre-styled-ui)はこの構造へ既定 CSS を追加するだけの薄いラッパーであり、CSS は持ちません。スタイル済みの表示例は Calendar を参照してください。

日付の実在性検証以外の入力値検証・ロケール依存の日付整形・フォーム送信処理は本部品の責務外であり、利用側が担います。

関連 API: fandhe-frontend-headless-ui API

Demo

枠線・余白は docs サイト側のデモ枠であり、fandhe-frontend-headless-ui 自体はスタイルを持ちません。

July 2026
SuMoTuWeThFrSa

Features

  • Root/Heading/PrevTrigger/NextTrigger/Table/TableHeader/TableRow/TableHeadCell/TableBody/TableCell/DayTrigger の 11 anatomy パーツを提供し、月表示・単一日付選択・min/max 範囲制約を持つ状態機械 Calendar を組み合わせる。
  • 「今日」は Calendar::new の today 引数として呼び出し側が明示的に渡す。SystemTime/Instant/js_sys 等の時刻取得 API を内部で一切使わない決定的な設計であり、同一入力から常に同一出力を返す。
  • table に role="grid"、table_row に role="row"、table_head_cell に role="columnheader"、table_cell に role="gridcell" + aria-selected を付与し、WAI-ARIA APG の grid パターンに従う。
  • day_trigger は選択日に data-selected、今日に data-today + aria-current="date"、表示月外の日付に data-outside-month、min/max 範囲外の日付に data-disabled + ネイティブ disabled + aria-disabled を出力する。
  • 範囲選択(range mode)・複数月表示・年/月ビュー切替は本コンポーネントのスコープ外(単一日付の選択のみを扱う)。
  • ark-ui/zag の data-focus/data-view/data-weekend/data-unavailable/range 系属性は出力しない(DOM ローカル状態・ビュー概念なし・locale 依存・range mode スコープ外のため。#1625 参考サイト突合結果)。
  • パート名 table-header(<thead>)/table-head-cell(<th>)は ark-ui(table-head/table-header)とはパート名の対応が入れ替わっている(本実装は要素の役割をそのまま表す命名)。
  • キーボード操作(矢印キー等での日付移動)は fandhe-frontend-wasm-full の keynav 配線(#1074/#1161)が担う。本コンポーネント(SSR 単体)はネイティブ <button> の Tab / Enter / Space のみを提供する。

Anatomy

root
  heading
  prev-trigger
  next-trigger
  table
    table-header
      table-row
        table-head-cell
    table-body
        table-cell
          day-trigger

API Reference

Arguments

NameTypeDefaultDescription
view_yeari32(必須)表示する年(0000..=9999)。範囲外は DateError::OutOfRange。
view_monthu8(必須)表示する月(1..=12)。
todayPlainDate(必須)「今日」として扱う日付。呼び出し側が明示的に渡す(内部で時刻取得 API を使わない決定的設計)。
selectedOption<PlainDate>None現在選択中の日付。
min / maxOption<PlainDate>None選択可能範囲の下限・上限。ともに Some で min > max なら DateError::InvalidDate。
week_startWeekday(必須)週の開始曜日。

Data Attributes

PartAttributeObserved Values
day-triggerdata-disabled(値なし)
day-triggerdata-outside-month(値なし)
day-triggerdata-selected(値なし)
day-triggerdata-today(値なし)
day-triggerdata-value2026-06-28, 2026-06-29, 2026-06-30, 2026-07-01, 2026-07-02, 2026-07-03, 2026-07-04, 2026-07-05, 2026-07-06, 2026-07-07, 2026-07-08, 2026-07-09, 2026-07-10, 2026-07-11, 2026-07-12, 2026-07-13, 2026-07-14, 2026-07-15, 2026-07-16, 2026-07-17, 2026-07-18, 2026-07-19, 2026-07-20, 2026-07-21, 2026-07-22, 2026-07-23, 2026-07-24, 2026-07-25, 2026-07-26, 2026-07-27, 2026-07-28, 2026-07-29, 2026-07-30, 2026-07-31, 2026-08-01
next-triggerdata-disabled(値なし)
prev-triggerdata-disabled(値なし)

Examples

範囲外の日付・前月移動の無効化

day_trigger の disabled と prev_trigger の disabled を true にすると、min/max 範囲外であることを示す data-disabled・ネイティブ disabled・aria-disabled が出力されます。

自前 CSS の最小例

headless-ui 自体はスタイルを持たないため、data-scope/data-part/data-selected/data-today/data-outside-month/data-disabled 属性セレクタで見た目を組み立てる最小例です。

利用者が data-scope / data-part / data-selected / data-today / data-outside-month / data-disabled 属性セレクタで自前 CSS を当てる最小例です。headless-ui 自体はスタイルを持ちません。

CSS
[data-scope="calendar"][data-part="table"] {
  border-collapse: collapse;
}
[data-scope="calendar"][data-part="day-trigger"] {
  width: 2rem;
  height: 2rem;
  border: none;
  border-radius: 4px;
}
[data-scope="calendar"][data-part="day-trigger"][data-selected] {
  background: #2563eb;
  color: #fff;
}
[data-scope="calendar"][data-part="day-trigger"][data-today] {
  font-weight: bold;
}
[data-scope="calendar"][data-part="day-trigger"][data-outside-month] {
  color: #9ca3af;
}
[data-scope="calendar"][data-part="day-trigger"][data-disabled] {
  opacity: 0.4;
}
[data-scope="calendar"][data-part="prev-trigger"]:focus-visible,
[data-scope="calendar"][data-part="next-trigger"]:focus-visible {
  outline: 2px solid #2563eb;
  outline-offset: 2px;
}

Accessibility

Keyboard Interactions

KeyDescription
Tabprev_trigger/next_trigger/day_trigger はいずれもネイティブ <button type="button"> であり、ブラウザ既定のフォーカス順で到達する(無効化時は disabled によりフォーカス対象から除外される)。
Space / Enterフォーカス中の prev_trigger/next_trigger/day_trigger をブラウザ既定動作で押下する(day_trigger は fandhe-frontend-wasm-full の keynav 配線で選択・prev_trigger/next_trigger は月移動をディスパッチする)。
ArrowLeft / ArrowRightfandhe-frontend-wasm-full の keynav 配線(#1074/#1161)が担う。フォーカス中の日付を ±1 日移動する(data-disabled のセルはスキップ、行末で次行へ、非循環)。
ArrowUp / ArrowDown同 keynav 配線が担う。フォーカス中の日付を ±7 日(1 週間)移動する。
Home / End同 keynav 配線が担う。フォーカス中の行の先頭・末尾の非 disabled セルへ移動する(zag の実装に合わせた挙動。ark-ui サイトの「月初/月末」という文言とは異なる)。
PageUp / PageDown同 keynav 配線が担う。prev_trigger/next_trigger への click 合成で月移動する(trigger が disabled のときは no-op)。

WAI-ARIA

AttributeDescription
roletable に "grid"、table_row に "row"、table_head_cell に "columnheader"、table_cell に "gridcell" を固定付与する。
aria-selectedtable_cell へ選択状態を反映する(day_trigger の data-selected とセットで選択状態を二重に表現する、WAI-ARIA grid パターンの慣行)。
aria-current今日の day_trigger へ "date"(AriaCurrent::Date)を付与する。
aria-disabledmin/max 範囲外の day_trigger、範囲下限/上限に到達した prev_trigger/next_trigger へ "true" を付与する。
aria-labelledbytable の labelledby が Some のとき、heading の id と対で関連付ける。
aria-labelday_trigger は ISO 8601 表記(例: "2026-07-25")を固定付与する。prev_trigger/next_trigger は既定値を持たないため、アイコンのみを子に置く場合はアクセシブル名を呼び出し側が attrs で渡す(例: ("aria-label", "Previous month"))。