Skip to content
fandhe-frontendcore v0.4.3
GitHub

Date Input

年・月・日を独立したセグメントとして編集する、WAI-ARIA の spinbutton パターンに従った unstyled 部品です。3 セグメントすべてが揃った場合のみ実在する日付か検証し、存在しない日付(例: 2 月 30 日)はセグメント値を保持したまま invalid 表示に倒します(fail-closed)。

ark-ui(zag.js の date-input machine)の Data Attributes 表・キーボード操作と突合済みです(イシュー #1626)。data-type(year/month/day)・data-value(入力済み)・data-editable(常時)・data-placeholder-shown(未入力)を各セグメントへ、data-focus を control/segment-group へ、data-readonly を全パーツへ付与します。状態機械の dispatch 語彙として increment/decrement(境界で wrap-around)・page-increment/page-decrement(PageUp/PageDown 相当、境界で clamp)・home/end・prev/next(矢印キーでのセグメント間移動相当)・backspace を提供しますが、実 DOM キーイベントへの配線(fandhe-frontend-wasm-full)は本部品の責務外です。

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

headless-ui はスタイルレスです。data-scope/data-part/data-* をセレクタに使い、自前の CSS を当てることができます(例: [data-scope="date-input"][data-part="segment"][data-type="year"])。

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

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

Demo

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

2026
07
22
yyyy
mm
dd
2026
01
01
2026
07
22
2024
02
30

Features

  • Root/Label/Control/SegmentGroup/Segment/HiddenInput の 6 anatomy パーツと、年・月・日をそれぞれ独立したセグメントとして編集する状態機械 DateInput を提供する。
  • 各 segment は role="spinbutton" + aria-valuemin/aria-valuemax を常に出力し、値が入力済みのときのみ aria-valuenow を追加する(WAI-ARIA spinbutton パターン)。
  • 3 セグメントすべてが揃った場合のみ実在する日付か検証する(fail-closed)。存在しない日付(例: 2 月 30 日)は is_invalid が true を返す状態としてセグメント値を保持したまま表示する(値を破棄しない)。
  • hidden_input パーツのみが name を持ち、確定済み日付を ISO 8601 文字列としてフォーム送信へ渡す。各 segment 自体は name を持たずフォーム送信に参加しない。
  • ark-ui(zag.js date-input machine)の Data Attributes 表と突合し、data-type(year/month/day)・data-value(入力済み)・data-editable(常時)・data-placeholder-shown(未入力)を segment へ、data-focus を control/segment-group へ、data-readonly を全パーツへ追加した(イシュー #1626)。
  • Increment/Decrement は境界で wrap-around する(例: year は 9999→0)。PageIncrement/PageDecrement(PageUp/PageDown 相当)・Home/End・Prev/Next(矢印キーでのセグメント間移動相当)・Backspace の状態遷移語彙を提供するが、実 DOM キーイベントへの配線は fandhe-frontend-wasm-full 側の責務(本コンポーネントは状態機械の dispatch 語彙のみを提供する)。
  • セグメント値の実在性チェック以外の入力値検証・ロケール依存の日付整形は本コンポーネントの責務外であり、利用者側が担う(docs/policy/intentional-non-adoption.md §3.25)。

Anatomy

root
  label
  control
    segment-group
      segment
    hidden-input

API Reference

Arguments

NameTypeDefaultDescription
kindDateSegment(必須)Year/Month/Day のいずれか。aria-label・未入力時のプレースホルダ・data-type を内部で決定する。
valueOption<&str>None現在の表示値。None のとき data-placeholder-shown を付与しプレースホルダを表示する。Some のとき data-value を付与する。
min / max&str(必須)aria-valuemin/aria-valuemax に出力する下限・上限の文字列表現。
propsDateInputPropsDateInputProps::default()disabled/readonly/invalid/focused の 4 フラグを束ねる構造体(root/label/control/segment_group/segment 共通)。focused は control/segment-group の data-focus にのみ反映され、root/label/segment は無視する。

Data Attributes

PartAttributeObserved Values
controldata-disabled(値なし)
controldata-focus(値なし)
controldata-invalid(値なし)
controldata-readonly(値なし)
hidden-inputdata-disabled(値なし)
labeldata-disabled(値なし)
labeldata-invalid(値なし)
labeldata-readonly(値なし)
rootdata-disabled(値なし)
rootdata-invalid(値なし)
rootdata-readonly(値なし)
segmentdata-disabled(値なし)
segmentdata-editable(値なし)
segmentdata-invalid(値なし)
segmentdata-placeholder-shown(値なし)
segmentdata-readonly(値なし)
segmentdata-typeday, month, year
segmentdata-value(値なし)
segment-groupdata-disabled(値なし)
segment-groupdata-focus(値なし)
segment-groupdata-invalid(値なし)
segment-groupdata-readonly(値なし)

Examples

実在しない日付(invalid)の表示

年・月・日すべてが揃っても実在しない日付(2 月 30 日)の場合、Day セグメントへ aria-invalid・data-invalid が付与されます。セグメント値自体は保持されたままです。

2026
02
30

Custom CSS

headless-ui が出力する data-* 属性を CSS セレクタとして利用する最小例です。

headless-ui はスタイルレスです。data-scope/data-part/data-* をセレクタに使い、以下のような CSS を自前で当てられます。

2026
mm
dd
CSS
[data-scope="date-input"][data-part="segment"] {
  border-radius: 4px;
  padding: 0 4px;
}

[data-scope="date-input"][data-part="segment"][data-type="year"] {
  min-width: 4ch;
}

[data-scope="date-input"][data-part="segment"][data-placeholder-shown] {
  color: #999;
}

[data-scope="date-input"][data-part="segment-group"][data-focus] {
  outline: 2px solid #06c;
}

[data-scope="date-input"][data-part="root"][data-invalid] [data-part="segment-group"] {
  border-color: #c00;
}

[data-scope="date-input"][data-part="segment"]:focus-visible {
  outline: 2px solid #06c;
  outline-offset: 2px;
}

Accessibility

Keyboard Interactions

KeyDescription
Tab各 segment(div role="spinbutton")は disabled でない限り tabindex="0" を持ち、ブラウザ既定の Tab 順に含まれる。
ArrowUp / ArrowDownフォーカス中セグメントを ±1("increment"/"decrement" dispatch)。境界で wrap-around する。実 DOM 配線は wasm-full 側。
PageUp / PageDownフォーカス中セグメントを ±PAGE_STEP("page-increment"/"page-decrement" dispatch、境界で clamp)。実 DOM 配線は wasm-full 側。
Home / Endフォーカス中セグメントを最小値/最大値へ("home"/"end" dispatch)。実 DOM 配線は wasm-full 側。
ArrowLeft / ArrowRightフォーカスを前後のセグメントへ移動("prev"/"next" dispatch、year↔month↔day の順・端で留まる)。実 DOM 配線は wasm-full 側。
Backspace / Delete値があれば消去し留まる。既に未入力なら前のセグメントへフォーカス移動("backspace" dispatch、Delete も同一 dispatch にマップする配線側契約)。実 DOM 配線は wasm-full 側。

WAI-ARIA

AttributeDescription
role (segment)各 segment へ "spinbutton" を固定付与する。
role (segment-group)segment_group へ "group" を固定付与する。aria-labelledby は呼び出し側が attrs 経由で label の id を配線する。
aria-valuemin / aria-valuemax各 segment へ常に出力する下限・上限。
aria-valuenowvalue が Some のときのみ segment へ出力する。
aria-invalidprops.invalid が true のとき segment へ "true" を付与する。
aria-readonlyprops.readonly が true のとき segment へ "true" を付与する。
aria-disabledprops.disabled が true のとき segment へ "true" を付与する(tabindex は省略される)。