Skip to content
fandhe-frontendcore v0.4.3
GitHub

Number Input

fandhe-frontend-headless-ui の number_input mod が提供する数値入力の unstyled 部品です。Root / Label / Control / Input / IncrementTrigger / DecrementTrigger / ValueText の 7 anatomy パーツで構成され、min/max/step に沿った値の正規化・境界到達時のトリガー無効化(data-disabled)を担います。連続量のため離散的な data-state は持ちません。

NumberInputFlags(disabled/readonly/required/invalid)は Root / Label / Control / Input / ValueText の全パーツで共通に使い、data-readonly は Root/Control/ValueText へ、data-required は Label のみへ反映されます(ark-ui/zag.js の number-input machine に倣った差分)。Control は role="group" を持ち、disabled/invalid に応じて aria-disabled/aria-invalid を出力します。dispatch は "increment"/"decrement"/"set"/"clear" に加えて "home"(値を min へ)/"end"(値を max へ)に対応します。参考サイトが持つ Scrubber パーツ(Pointer Lock API 前提)は非採用です。

/themes/ 側の Input(Chakra ライクな variant/size を持つスタイル層)と異なり、CSS を一切持たず、増減操作の実 DOM 配線もクライアントランタイム側の責務です。

スタイル済みの表示例は Number Input を参照してください。

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

Demo

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

3

Features

  • Root / Label / Control / Input / IncrementTrigger / DecrementTrigger / ValueText の 7 anatomy パーツを提供する(data-state は持たない。連続量のため境界到達の 2 値のみを各トリガーの disabled/data-disabled で表現する。ValueText はイシュー #1613 で追加)。
  • min/max/step/value を fail-closed に正規化し、step の小数桁数へ丸めてから [min, max] へ clamp する(浮動小数点ドリフト対策)。
  • input は type="text" + role="spinbutton"(WAI-ARIA spinbutton パターン)で意味論を担い、aria-valuemin/aria-valuemax を常時、aria-valuenow は値が確定しているときのみ出力する。autocomplete="off"/autocorrect="off"/spellcheck="false"/aria-roledescription="numberfield"(イシュー #1613)も常時出力する。
  • control は role="group" を持ち、disabled/invalid に応じて aria-disabled/aria-invalid を出力する(イシュー #1613)。root/control の data-readonly、label の data-required(label のみ、zag.js に倣う)も同イシューで追加した。
  • dispatch("increment"/"decrement"/"set"/"clear"/"home"/"end")と hydration(data-hydrate-value/-min/-max/-step)は fail-closed(パース不能・非有限値は HydrateError で拒否)。"home"/"end"(イシュー #1613)は値を min/max へ設定する。

Anatomy

root
  label
  control
    decrement-trigger
    input
    increment-trigger
  value-text

API Reference

Arguments

NameTypeDefaultDescription
root/label/control/value_text(flags)NumberInputFlagsNumberInputFlags::default()disabled/readonly/required/invalid の 4 bool をまとめた薄い構造体(clippy too_many_arguments 回避、イシュー #1613 で input 専用から全パーツ共通化)。required は label のみが data-required へ反映する。
label(input_id)Option<&str>—Some のとき input の id と対で for 属性を出力する。
input(name)&str—ネイティブ name 属性。
input(id)Option<&str>—Some のとき id 属性を出力する(label(input_id) の関連付け先)。
input(value)Option<&str>—現在値の整形済み文字列。None(未入力)なら aria-valuenow/value 属性ごと出力しない。
input(min)&str—aria-valuemin として常時出力する整形済み文字列。
input(max)&str—aria-valuemax として常時出力する整形済み文字列。
increment_trigger/decrement_trigger(input_id)Option<&str>—Some のとき aria-controls で input と関連付ける。
increment_trigger/decrement_trigger(disabled)bool—境界到達(can_increment/can_decrement が false)と全体無効化を合成した最終値。true でネイティブ disabled + data-disabled を出力する。

Data Attributes

PartAttributeObserved Values
controldata-disabled(値なし)
controldata-invalid(値なし)
controldata-readonly(値なし)
decrement-triggerdata-disabled(値なし)
increment-triggerdata-disabled(値なし)
inputdata-disabled(値なし)
inputdata-invalid(値なし)
inputdata-readonly(値なし)
inputdata-required(値なし)
labeldata-disabled(値なし)
labeldata-invalid(値なし)
labeldata-required(値なし)
rootdata-disabled(値なし)
rootdata-invalid(値なし)
rootdata-readonly(値なし)

Examples

Disabled

全体を無効化した NumberInput。両トリガーがネイティブ disabled を持ち、input にも data-disabled が付く。

Read-only

readonly を立てた NumberInput。root/control/input に data-readonly が付き、両トリガーは境界到達で disabled になる(イシュー #1613)。

自前 CSS の最小例

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

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

CSS
[data-scope="number-input"][data-part="control"] {
  display: inline-flex;
  align-items: center;
  border: 1px solid #888;
  border-radius: 4px;
}
[data-scope="number-input"][data-part="input"] {
  border: none;
  padding: 0.25rem 0.5rem;
  width: 4rem;
}
[data-scope="number-input"][data-part="input"][data-invalid] {
  outline: 2px solid #dc2626;
}
[data-scope="number-input"][data-part="control"][data-readonly] {
  background: #f3f4f6;
}
[data-scope="number-input"][data-part="root"][data-disabled] {
  opacity: 0.5;
}

Accessibility

Keyboard Interactions

KeyDescription
ArrowUpstep 分だけ増加する("increment" dispatch、payload は input の name 属性値。fandhe-frontend-wasm-full の number_input::resolve_dispatches で配線済み、イシュー #1613 PR #1881)。
ArrowDownstep 分だけ減少する("decrement" dispatch、同上)。
Home値を min に設定する("home" dispatch、payload は input の name 属性値。fandhe-frontend-wasm-full の number_input::resolve_dispatches で配線済み、イシュー #1613 PR #1881)。
End値を max に設定する("end" dispatch、同上)。
Enterinput 要素にタイプ中の値を確定する("set" dispatch、payload は input.value。fandhe-frontend-wasm-full の number_input::resolve_dispatches で配線済み、イシュー #1613 PR #1881。不正な文字列は decode_action が fail-closed に拒否する)。
(複数インスタンスの識別)同一 root 配下に複数の NumberInput を置く場合、input パーツへ data-action-input="<アプリ定義のアクション名>" を付けると Enter/Arrow の確定 dispatch("set")がその名前へ上書きされる(crate::events の input イベント配線と同じ属性契約)。increment/decrement/home/end/clear は固定アクション名のまま payload に input の name 属性値が載るため、アプリの decode_action は name/payload の組み合わせで更新先を区別できる(イシュー #1613 PR #1881 codex-review P1 是正)。

WAI-ARIA

AttributeDescription
role="spinbutton" (input)WAI-ARIA spinbutton パターン。ネイティブ <input type="number"> ではなく type="text" を使うため native な上下キー増減はブラウザ標準では成立しないが、fandhe-frontend-wasm-full の keydown 配線(ArrowUp/ArrowDown/Home/End/Enter)が "increment"/"decrement"/"home"/"end"/"set" を dispatch することで同等の操作を実現する(イシュー #1613 PR #1881、下記 Keyboard 節参照)。
aria-roledescription="numberfield" (input)常時出力する(イシュー #1613)。
aria-valuemin / aria-valuemax (input)正規化済みの min/max を常時出力する。
aria-valuenow (input)現在値が確定している(value が Some)ときのみ出力する。
role="group" (control)呼び出し側 attrs の role 指定にかかわらず常時固定出力する(CONTROL_RESERVED により呼び出し側の同名キーは常に除去される、イシュー #1613)。
aria-disabled / aria-invalid (control)disabled/invalid が true のときのみ出力する(イシュー #1613)。