figma guide
Designing toggle switches and checkboxes in Figma: states, groups, and handoff
Design toggle switches and checkboxes in Figma with on/off states, indeterminate, grouped layouts, form validation, and Dev Mode specs engineers can ship without guessing.
- Published
- Updated
- Jun 15, 2026
- Read time
- 7 min
- Level
- Beginner
Quick answer
Checkboxes let users select one or more independent options; toggle switches flip a single setting on or off immediately. Build separate component sets: a Checkbox with variants for checked=unchecked | checked | indeterminate and state=default | focus | error | disabled, and a Switch with on=off | on plus the same interaction states. Use checkboxes for multi-select lists and consent; use switches for binary settings that apply without a Save button. Pair with forms, sliders, and accessibility plugins. Document label placement, group semantics, and whether changes save instantly in Dev Mode. Start from the Figma guides hub for input primitives.
Who this is for
- Product designers shipping settings panels, filters, consent flows, and bulk-select tables.
- Design system teams standardizing when to use checkbox vs switch vs radio group.
- Engineers implementing ARIA roles, indeterminate parent rows, and instant-save vs form-submit behavior.
Checkbox vs switch vs radio: when to use which
| Control | Selection model | Typical use | Saves when |
|---|---|---|---|
| Checkbox | Independent on/off per item | Multi-select filters, terms acceptance, table row select | Form submit or immediate (document) |
| Switch | Single binary setting | Notifications on/off, dark mode, feature flags | Usually immediate |
| Radio group | Exactly one of N | Plan tier, shipping method | Form submit |
| Segmented control | One of few visible options | View mode, time range | Immediate |
Verdict: if the copy reads “Enable notifications,” use a switch. If it reads “I agree to the terms” or “Select all rows,” use a checkbox. If options are mutually exclusive, use segmented controls or radio groups instead.
Checkbox component anatomy
| Part | Purpose | Spec tip |
|---|---|---|
| Hit target | Tap/click area | Min 44×44px touch; box can be 16–20px |
| Box | Visual checked state | 16px sm, 20px md standard |
| Checkmark / dash | Checked / indeterminate | Centered; 2px stroke at md |
| Label | Describes the option | Clickable; wraps on mobile |
| Helper text | Extra context | Below label, not inside box |
| Error message | Validation failure | ”You must accept to continue” |
Checkbox
├── Variant: checked=unchecked | checked | indeterminate
├── Variant: state=default | focus | error | disabled
├── Variant: size=sm | md
├── Layer: Row (auto layout horizontal, gap 8–12)
│ ├── Box (frame with corner radius 4px)
│ │ ├── Checkmark icon (checked)
│ │ └── Dash icon (indeterminate)
│ └── LabelBlock
│ ├── Label (text/body)
│ └── Helper (text/body-sm, optional)
└── Layer: Error text (optional, below row)
Bind checked colors to semantic color tokens. Use interactive components for hover on the row, not just the box.
Checkbox states
| State | Box | Label | Notes |
|---|---|---|---|
| Unchecked | Empty border | Default text | Neutral border token |
| Checked | Filled + checkmark | Default text | Use brand or semantic fill |
| Indeterminate | Filled + horizontal dash | Default text | Parent row in nested lists |
| Focus | Focus ring on box or row | Unchanged | 2px ring; never remove for “clean” UI |
| Error | Error border | Error label optional | Pair with message below |
| Disabled | Muted fill/border | Muted text | cursor: not-allowed in spec |
Indeterminate appears when a parent checkbox controls children and only some are selected—common in tables with “select all” headers.
Switch component anatomy
| Part | Purpose | Spec tip |
|---|---|---|
| Track | Background rail | 44×24px md common; pill radius |
| Thumb | Sliding circle | 20px diameter; 2px inset from track |
| Label | Setting name | Left of switch (settings) or right (compact) |
| Description | Secondary copy | Below label for dense settings |
Switch
├── Variant: on=off | on
├── Variant: state=default | focus | disabled
├── Variant: size=sm | md
├── Layer: Row (auto layout horizontal, space-between or label-left)
│ ├── LabelBlock (optional)
│ │ ├── Label
│ │ └── Description
│ └── Track
│ └── Thumb (position: left | right)
└── Layer: Helper / error (optional)
Animate thumb position in prototypes with smart animate between on/off frames if stakeholders need motion; document instant toggle for engineering.
Switch states
| State | Track | Thumb | Notes |
|---|---|---|---|
| Off | Neutral gray | Left | Default resting |
| On | Brand / success fill | Right | High contrast vs off |
| Focus | Unchanged | Focus ring on track | Visible keyboard path |
| Disabled off | Muted track | Muted thumb | Entire control inactive |
| Disabled on | Muted brand | Muted thumb | Show locked-on settings clearly |
Do not use a switch for destructive actions without confirmation—pair delete flows with modals.
Layout patterns for groups
| Pattern | Layout | Best for |
|---|---|---|
| Vertical stack | Auto layout vertical, 12–16px gap | Settings, filters, consent |
| Inline pair | Two checkboxes in a row | Weekday toggles (Mon–Fri) |
| Nested tree | Parent + indented children | Permissions, folder pickers |
| Table header | Checkbox in column header | Bulk actions on data tables |
| Card list | Checkbox leading each card | Multi-select inbox |
For select all in tables, design three frames: none selected, all selected, partial (indeterminate parent).
Pairing with other patterns
| Need | Pattern | Link |
|---|---|---|
| Form field wrapper | Label + checkbox + error | Forms guide |
| Filter sidebar | Checkbox list | Search UI |
| Settings page | Switch rows | Accordions for grouped settings |
| Required consent | Checkbox + submit disabled | Progress steppers |
| Status tags | Do not confuse with chips | Chips are display; checkboxes are input |
Accessibility checklist
| Requirement | Checkbox | Switch |
|---|---|---|
| Role | role="checkbox" | role="switch" |
| State | `aria-checked=“true | false |
| Label | <label for> or aria-labelledby | Same |
| Group | role="group" + aria-labelledby for sets | Fieldset legend pattern |
| Focus | Visible focus ring | Visible focus ring |
| Disabled | aria-disabled or native disabled | Same |
| Error | aria-invalid="true" + aria-describedby | Same |
Run accessibility plugins on contrast for unchecked boxes and off-state tracks—gray-on-white often fails WCAG.
Prototyping limits
Figma cannot persist checkbox state across navigations. For demos:
- Build frames: unchecked, checked, indeterminate, error, disabled.
- Use component properties or swap instances for settings screens.
- For switches, smart-animate thumb position between on/off variants.
Organize flows with sections per settings area.
Handoff to engineering
| Deliverable | Checkbox | Switch |
|---|---|---|
checked / on | boolean | boolean |
indeterminate | boolean (checkbox only) | n/a |
disabled | boolean | boolean |
name / value | for form posts | setting key |
onChange timing | on click | on click |
| Save behavior | immediate vs form submit | usually immediate |
| Label click | toggles control | toggles control |
| Group label | string for fieldset | section heading |
| Error message | string | string |
Include both primitives in your Dev Mode handoff checklist. Publish under Patterns / Forms in your team library.
Real-world examples
Notification settings (switches)
List of switches with label left, control right. Each row: title + one-line description. Off states use neutral track; on uses brand green. Disabled row when user lacks permission—muted with lock icon.
Terms acceptance (checkbox)
Single required checkbox above primary submit. Error state on submit if unchecked: red border + “Accept the terms to continue.” Submit button stays enabled but shows error—document preferred validation pattern.
Data table bulk select (checkboxes)
Header checkbox cycles: unchecked → all → indeterminate when partial. Row checkboxes independent. Toolbar appears when ≥1 row selected—link to badges for selection count.
Common mistakes
| Mistake | Consequence | Fix |
|---|---|---|
| Switch for multi-select | Wrong control shipped | Use checkbox list |
| Checkbox for mutually exclusive options | Multiple selections allowed | Use radio group |
| Tiny hit target (12px box only) | Miss taps on mobile | 44px row min height |
| No indeterminate state | Broken “select all” | Add third variant |
| Label not clickable | Frustrating UX | Wire label to control in spec |
| Switch requires Save button | Confusing mental model | Instant apply or use checkbox |
| Focus ring removed | Keyboard users lost | Keep 2px focus ring token |
| Same component for checkbox and switch | Wrong anatomy | Separate component sets |
FAQ
Checkbox or switch for “Remember me”?
Checkbox—it is part of a form submit flow, not an instant system setting.
Switch or checkbox for dark mode?
Switch—users expect immediate theme change without Save.
Where does indeterminate appear?
Parent checkboxes in trees and table headers when children are partially selected.
Checkbox inside a modal?
Yes—common for “Don’t show again” or destructive confirm. Keep label readable at modal width.
Bottom line
Treat checkboxes and switches as distinct primitives with clear selection semantics, full state matrices, and honest save behavior. Document indeterminate, group labels, and table bulk-select in Dev Mode. Continue with forms, segmented controls, sliders, and the tutorials hub.
§ Keep reading