You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs(Switch): restructure page to match component docs spec
Reorder sections to Usage → Anatomy → Examples → Recipes → Accessibility → FAQ,
move Group and Indeterminate live demos out of Recipes into a new Examples
section, correct the hidden input description to match the source (native
checkbox input with role="switch"), split the data attribute table to reflect
that Track and Thumb emit data-state but not data-disabled, and add a FAQ
section.
Copy file name to clipboardExpand all lines: apps/docs/src/pages/components/forms/switch.md
+69-61Lines changed: 69 additions & 61 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -18,17 +18,12 @@ related:
18
18
19
19
# Switch
20
20
21
-
A headless switch component with dual-mode support: standalone boolean binding or group multi-selection with tri-state.
21
+
A switch for on/off state or multi-selection groups with tri-state support.
22
22
23
23
<DocsPageFeatures:frontmatter />
24
24
25
25
## Usage
26
26
27
-
The Switch component supports two modes:
28
-
29
-
-**Standalone mode**: Use `v-model` on `Switch.Root` for simple boolean state
30
-
-**Group mode**: Wrap in `Switch.Group` for multi-selection with array v-model
31
-
32
27
::: example
33
28
/components/switch/basic
34
29
@@ -94,51 +89,40 @@ A standalone boolean switch with label and slide animation.
94
89
</template>
95
90
```
96
91
97
-
## Accessibility
98
-
99
-
The Switch.Root component renders as a button and handles all ARIA attributes automatically:
100
-
101
-
-`role="switch"` for proper semantics
102
-
-`aria-checked` reflects state (`true`, `false`, or `"mixed"`)
103
-
-`aria-disabled` when switch is disabled
104
-
-`aria-label` from the `label` prop
105
-
-`tabindex="0"` for keyboard focus (removed when disabled)
106
-
- Space key toggles the switch
107
-
108
-
For custom implementations, use `renderless` mode and bind the `attrs` slot prop to your element:
92
+
## Examples
109
93
110
-
```vue
111
-
<template>
112
-
<Switch.Root v-slot="{ attrs }" renderless>
113
-
<div v-bind="attrs">
114
-
<!-- Custom switch visual -->
115
-
</div>
116
-
</Switch.Root>
117
-
</template>
118
-
```
94
+
::: example
95
+
/components/switch/group
119
96
120
-
##Recipes
97
+
### Switch Group
121
98
122
-
### Group Mode
99
+
Multi-select switch group managing an array of connectivity options (WiFi, Bluetooth, Location).
123
100
124
-
Wrap switches in `Switch.Group` for multi-selection with array-based v-model:
101
+
:::
125
102
126
103
::: example
127
-
/components/switch/group
104
+
/components/switch/indeterminate
128
105
129
-
### Switch Group
106
+
### Select-All Switch
130
107
131
-
Multi-select switch group managing an array of connectivity options (WiFi, Bluetooth, Location).
108
+
A "select all" switch with indeterminate state over nested permission toggles.
132
109
133
110
:::
134
111
112
+
The `SelectAll` component:
113
+
- Binds to the group's `isAllSelected` and `isMixed` state
114
+
- Calls `toggleAll` on click
115
+
- Does NOT register as a group item
116
+
- Sets `aria-checked="mixed"` and `data-state="indeterminate"` when partially selected
117
+
118
+
## Recipes
119
+
135
120
### Form Integration
136
121
137
-
When the `name` prop is provided on `Switch.Root`, a hidden native checkbox is automatically rendered for form submission:
122
+
Pass the `name` prop on `Switch.Root` and a hidden native `<input type="checkbox">` is rendered automatically — no `Switch.HiddenInput` placement is required. The input is visually hidden, `inert`, and `tabindex="-1"`, so it only participates in `FormData` submission:
138
123
139
124
```vue
140
125
<template>
141
-
<!-- Auto-renders hidden input for form submission -->
142
126
<Switch.Root name="notifications" value="on">
143
127
<Switch.Track>
144
128
<Switch.Thumb />
@@ -147,56 +131,80 @@ When the `name` prop is provided on `Switch.Root`, a hidden native checkbox is a
147
131
</template>
148
132
```
149
133
150
-
For custom form integration, use `Switch.HiddenInput` explicitly:
134
+
Place `Switch.HiddenInput` explicitly only when you need to override the auto-rendered name, value, or form association:
Use `Switch.SelectAll` within a group for "select all" patterns. It automatically reflects the group's aggregate state and toggles all items on click:
167
-
168
-
::: example
169
-
/components/switch/indeterminate
170
-
171
-
### Select-All Switch
172
-
173
-
A "select all" switch with indeterminate state over nested permission toggles.
174
-
175
-
:::
176
-
177
-
The `SelectAll` component:
178
-
- Binds to the group's `isAllSelected` and `isMixed` state
179
-
- Calls `toggleAll` on click
180
-
- Does NOT register as a group item
181
-
- Sets `aria-checked="mixed"` and `data-state="indeterminate"` when partially selected
182
-
183
148
### Styling with Data Attributes
184
149
185
-
Switch components expose `data-state`attributes for CSS styling:
150
+
Switch subcomponents expose data attributes for CSS styling without conditional classes. `Switch.Root` and `Switch.SelectAll` emit both `data-state`and `data-disabled`, while `Switch.Track` and `Switch.Thumb` emit only `data-state` (they inherit disabled styling from the Root ancestor):
186
151
187
152
| Attribute | Values | Components |
188
153
|-----------|--------|------------|
189
-
|`data-state`|`checked`, `unchecked`, `indeterminate`| Root, Track, Thumb |
The Switch.Root component renders as a button and handles all ARIA attributes automatically:
170
+
171
+
-`role="switch"` for proper semantics
172
+
-`aria-checked` reflects state (`true`, `false`, or `"mixed"`)
173
+
-`aria-disabled` when switch is disabled
174
+
-`aria-label` from the `label` prop
175
+
-`tabindex="0"` for keyboard focus (removed when disabled)
176
+
- Space key toggles the switch
177
+
178
+
For custom implementations, use `renderless` mode and bind the `attrs` slot prop to your element:
179
+
180
+
```vue
181
+
<template>
182
+
<Switch.Root v-slot="{ attrs }" renderless>
183
+
<div v-bind="attrs">
184
+
<!-- Custom switch visual -->
185
+
</div>
186
+
</Switch.Root>
187
+
</template>
188
+
```
189
+
190
+
::: faq
191
+
192
+
??? When should I use Switch vs Checkbox?
193
+
194
+
Use `Switch` for settings that take immediate effect, like toggling a feature on or off (WiFi, notifications, dark mode). Use `Checkbox` for selections that are committed later — form submissions, multi-select lists, and "I agree" confirmations. The ARIA roles (`switch` vs `checkbox`) communicate this intent to assistive technology.
195
+
196
+
??? Why does my form submission miss the switch value?
197
+
198
+
`Switch.Root` only renders the hidden native input when a `name` prop is set. Without `name`, the switch is purely visual and won't appear in `FormData`. Add `name="myField"` (and optionally `value`) to participate in form submission.
199
+
200
+
??? How do I animate the thumb sliding?
201
+
202
+
Apply a CSS `transition` to `Switch.Thumb` (or `Switch.Track`) and use the `data-[state=checked]:` variant to change its transform. For example, `class="transition-transform data-[state=checked]:translate-x-5"` slides the thumb when toggled. No JavaScript event handling is needed — the data attribute flip drives the animation.
203
+
204
+
??? Can I use Switch.Root without the Track and Thumb subcomponents?
205
+
206
+
Yes. `Switch.Track` and `Switch.Thumb` are purely cosmetic — they read switch state from context to render the rail and knob. You can omit them entirely and render your own visual using the `attrs` slot prop on `Switch.Root`, or use `renderless` mode for full control over the rendered element.
0 commit comments