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 自体はスタイルを持ちません。
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-textAPI Reference
Arguments
| Name | Type | Default | Description |
|---|---|---|---|
root/label/control/value_text(flags) | NumberInputFlags | NumberInputFlags::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
| Part | Attribute | Observed Values |
|---|---|---|
control | data-disabled | (値なし) |
control | data-invalid | (値なし) |
control | data-readonly | (値なし) |
decrement-trigger | data-disabled | (値なし) |
increment-trigger | data-disabled | (値なし) |
input | data-disabled | (値なし) |
input | data-invalid | (値なし) |
input | data-readonly | (値なし) |
input | data-required | (値なし) |
label | data-disabled | (値なし) |
label | data-invalid | (値なし) |
label | data-required | (値なし) |
root | data-disabled | (値なし) |
root | data-invalid | (値なし) |
root | data-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 自体はスタイルを持ちません。
[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
| Key | Description |
|---|---|
| ArrowUp | step 分だけ増加する("increment" dispatch、payload は input の name 属性値。fandhe-frontend-wasm-full の number_input::resolve_dispatches で配線済み、イシュー #1613 PR #1881)。 |
| ArrowDown | step 分だけ減少する("decrement" dispatch、同上)。 |
| Home | 値を min に設定する("home" dispatch、payload は input の name 属性値。fandhe-frontend-wasm-full の number_input::resolve_dispatches で配線済み、イシュー #1613 PR #1881)。 |
| End | 値を max に設定する("end" dispatch、同上)。 |
| Enter | input 要素にタイプ中の値を確定する("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
| Attribute | Description |
|---|---|
| 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)。 |