Switch
fandhe-frontend-headless-ui の switch mod が提供するオン/オフ切り替えの unstyled 部品です。Root(<label>)/ Control / Thumb / Label / HiddenInput の 5 anatomy パーツを持ち、crate::state::Checkable を埋め込んだチェック状態機械(data-state は "checked"/"unchecked"、Checkbox/RadioGroup と共有語彙)を備えます。意味論・フォーム送信はネイティブ <input type="checkbox" role="switch">(HiddenInput)に委ねる構造です。
/themes/ 側の Switch(Chakra ライクな variant/size を持つスタイル層)と異なり、CSS を一切持ちません。
スタイル済みの表示例は Switch を参照してください。
関連 API: fandhe-frontend-headless-ui API
Demo
枠線・余白は docs サイト側のデモ枠であり、fandhe-frontend-headless-ui 自体はスタイルを持ちません。
Features
- Root(
<label>)/ Control / Thumb / Label / HiddenInput の 5 anatomy パーツと、crate::state::Checkableを埋め込んだチェック状態機械を提供する。 data-state値語彙は"checked"/"unchecked"(crate::state::Checkableが一元管理、Checkbox/RadioGroup と共有)。hidden_inputは<input type="checkbox" role="switch">(WAI-ARIA APG 準拠)。native のcheckedがブラウザによってaria-checkedへ自動マップされるため、aria-checkedを明示付与しない(二重読み上げ防止)。rootが<label>のため、内包するhidden_inputとの暗黙のラベル関連付けが JS なしで成立する(for/idの配線が不要)。- イシュー #1622(ark-ui / Radix Primitives との参照突合)で
SwitchProps(disabled/readonly/invalid/required)を新設し、data-disabled/data-invalid/data-required/data-readonlyを全 5 パーツへ一律反映するよう是正した(従来は root/control のdata-disabledのみだった)。 - 呼び出し側
attrsにdata-state/data-disabled/data-invalid/data-required/data-readonly/aria-checked/aria-invalid/type/role/checked/name/value/disabled/requiredと同名キー(大文字小文字無視)を渡しても fail-closed で除去し、状態の偽装を防ぐ(イシュー #1622 で追加)。 - 参考サイトとの意図的な差分(
data-hover/data-active/data-focus非出力、Enter キー非配線、readonly時の native トグル抑止なし、Radix のbutton role="switch"パターン不採用)はcrates/headless-ui/src/switch.rsモジュール doc「参考サイトとの意図的な差分」節を参照。
Anatomy
root
hidden-input
control
thumb
labelAPI Reference
Arguments
| Name | Type | Default | Description |
|---|---|---|---|
root/control/thumb/label(checked) | bool | — | data-state の checked/unchecked を決める。 |
root/control/thumb/label/hidden_input(props) | &SwitchProps | — | disabled/readonly/invalid/required の 4 フラグ束。全パーツへ対応する data-* を一律反映する(イシュー #1622)。 |
hidden_input(name, value) | &str, &str | — | ネイティブ name/value 属性。 |
hidden_input(checked) | bool | — | true のときのみネイティブ checked 存在属性を出力する。 |
hidden_input(props.disabled) | bool | — | true のときのみネイティブ disabled 存在属性を出力する。 |
hidden_input(props.required) | bool | — | true のときネイティブ required + data-required を出力する。 |
hidden_input(props.invalid) | bool | — | true のとき aria-invalid="true" + data-invalid を出力する(イシュー #1622 で追加)。 |
hidden_input(props.readonly) | bool | — | true のとき data-readonly を出力する。ネイティブ readonly 属性はチェックボックス/スイッチに意味を持たないため付与しない(イシュー #1622 で追加)。 |
Data Attributes
| Part | Attribute | Observed Values |
|---|---|---|
control | data-disabled | (値なし) |
control | data-invalid | (値なし) |
control | data-readonly | (値なし) |
control | data-required | (値なし) |
control | data-state | checked, unchecked |
hidden-input | data-disabled | (値なし) |
hidden-input | data-invalid | (値なし) |
hidden-input | data-readonly | (値なし) |
hidden-input | data-required | (値なし) |
hidden-input | data-state | checked, unchecked |
label | data-disabled | (値なし) |
label | data-invalid | (値なし) |
label | data-readonly | (値なし) |
label | data-required | (値なし) |
label | data-state | checked, unchecked |
root | data-disabled | (値なし) |
root | data-invalid | (値なし) |
root | data-readonly | (値なし) |
root | data-required | (値なし) |
root | data-state | checked, unchecked |
thumb | data-disabled | (値なし) |
thumb | data-invalid | (値なし) |
thumb | data-readonly | (値なし) |
thumb | data-required | (値なし) |
thumb | data-state | checked, unchecked |
Examples
Disabled, checked
checked: true + props.disabled: true の組み合わせ。hidden_input にネイティブ checked/disabled の両方が存在属性として出力される。
自前 CSS の最小例
利用者が data-scope / data-part / data-state / data-focus-visible / data-disabled / data-invalid 属性セレクタで自前 CSS を当てる最小例です。
利用者が data-scope / data-part / data-state / data-focus-visible / data-disabled / data-invalid 属性セレクタで自前 CSS を当てる最小例です。headless-ui 自体はスタイルを持ちません。
[data-scope="switch"][data-part="control"] {
width: 2.5rem;
height: 1.4rem;
border-radius: 999px;
background: #ccc;
}
[data-scope="switch"][data-part="control"][data-state="checked"] {
background: #2563eb;
}
[data-scope="switch"][data-part="thumb"] {
width: 1.1rem;
height: 1.1rem;
border-radius: 999px;
background: #fff;
}
[data-scope="switch"][data-part="thumb"][data-state="checked"] {
transform: translateX(1.1rem);
}
[data-scope="switch"][data-part="control"][data-focus-visible] {
outline: 2px solid #2563eb;
outline-offset: 2px;
}
[data-scope="switch"][data-part="root"][data-disabled] {
opacity: 0.5;
}
[data-scope="switch"][data-part="control"][data-invalid] {
border: 2px solid #dc2626;
}
Accessibility
Keyboard Interactions
| Key | Description |
|---|---|
| Space | hidden_input はネイティブ <input type="checkbox"> であり、Space キーでのトグルはブラウザ標準操作として成立する(JS 配線不要)。 |
| Enter | ark-ui / Radix は Enter でもトグルするが、本実装は native checkbox をそのまま使うため Enter では反応しない(意図的非採用。WAI-ARIA APG の Switch パターンでは Enter は Optional 扱い。詳細は crates/headless-ui/src/switch.rs モジュール doc 参照)。 |
WAI-ARIA
| Attribute | Description |
|---|---|
| aria-hidden="true" (control) | 装飾専用パーツとして固定付与する(意味論は hidden_input が担う)。 |
| aria-checked | hidden_input へ明示付与しない。native の <input type="checkbox" role="switch"> の checked 状態がブラウザにより自動マップされるため(二重読み上げ防止)。 |
| aria-invalid="true" (hidden_input) | props.invalid が true のときのみ出力する(イシュー #1622 で追加)。 |