Designing the complex form

Part 03 · Field types

Checkbox, radio, toggle — and the decision between them

Three controls, three meanings, picked nearly at random in most products. The semantic differences and the cost of getting them wrong.

01

Three controls, three meanings

Checkbox, radio, and toggle look interchangeable in a comp. They're not. They carry three different contracts with the user, and breaking the contract is the cheapest way to make a familiar UI feel wrong.

Checkbox

Form state. Multi-select or single binary choice. Applied on submit. The user can change their mind as many times as they like before submitting.

Radio

Form state. Single-select from 2+ visible options. Applied on submit. The user picks one; choosing another deselects the first.

Toggle

Live state. Single binary option. Applied immediately. Flipping it changes something in the world right now — a setting saves, a feature activates.

Checkbox and radio wait for submit. Toggle changes the world the moment you flip it. Get this backwards and you've shipped a destructive UI.

02

Toggle — for the world, not the form

A toggle's defining property is that flipping it changes something immediately. Use it for settings, preferences, on/off features — places where the change takes effect as soon as the user makes it.

Using a toggle as a form control — where the state only applies on submit — is the most common misuse. It looks modern in a comp. It breaks the user's expectation in production. The user flips the toggle, sees nothing happen, doesn't realize they have to scroll to find Save, and abandons.

<button
  role="switch"
  aria-checked="true"
  aria-label="Enable dark mode"
  type="button"
>...</button>
The ARIA role is switch, not checkbox

03

Radio — mutually exclusive form choice

Use radios when there are 2 to 5 visible options, exactly one will be picked, and the choice is applied on submit. Above five options, the radios start crowding the form — switch to a select. Below two, you have a binary, which is a single checkbox or a toggle.

  • All options visible at once. If they don't fit on the screen, you have too many — change the control.
  • Pre-select a default only when there's a sensible one. Don't pre-select to look tidy; "no selection" can be the right state, and pre-selecting biases the user.
  • Group radios with a fieldset and legend. The legend is the question; each radio is an answer. Screen readers depend on this.
  • Selection moves with arrow keys, not with Tab. Tab moves to the group; arrow keys select within it.

04

Checkbox — multi-select form choice

Use checkboxes for multi-select within a fixed list, or for a single binary form choice that gets applied on submit. "Select the days you're available" is multi-select. "I agree to the terms" is a single binary.

  • Each checkbox is independent. Picking one doesn't change another. (If picking one needs to deselect others, you have radios.)
  • Label each checkbox with what it does. Not "On" or "Enabled" — the action.
  • Above roughly ten options, the field is the wrong shape. Switch to a multi-select with search, or a longer list with category groupings.
  • Indeterminate state exists (aria-checked="mixed") for parent checkboxes in tree structures. Use it; don't fake it with a different visual.

05

The decision matrix

When the form is being designed, the question to ask in order:

  1. 01Does the change take effect immediately, before any submit? Use a toggle. Stop here.
  2. 02Does the change apply on submit, and the user picks more than one from a list? Use checkboxes.
  3. 03Does the change apply on submit, the user picks exactly one, and there are 2–5 visible options? Use radios.
  4. 04Does the change apply on submit, the user picks exactly one, and there are 6 or more options, or the options are too long to show inline? Use a select.
  5. 05Is it a single binary form choice (I agree, send me updates)? Use one checkbox.

The matrix isn't an opinion. The user's mental model of these controls is decades old and uniform across products. The cost of breaking it is silent — users will use the UI and feel that something is off without being able to say what.

06

Where state lives, and what that means for failures

Checkboxes and radios are easy — state lives inside the form, the network only touches it on submit. If submit fails, the form remembers what was checked and shows it back.

Toggles are harder because their state lives in the world. Flipping a toggle usually triggers a network call, and the network can fail. The pattern that works:

  1. 01Flip the toggle optimistically — show the new state immediately so the UI feels responsive.
  2. 02Fire the network call in the background.
  3. 03On success, do nothing visible. The optimistic state was correct.
  4. 04On failure, revert the toggle and surface an error toast with a Retry. Make sure the toggle's visual state actually moves back — half the broken implementations forget this and leave the toggle stuck in a state that doesn't match the server.

A toggle that lies about server state is worse than a toggle that takes half a second to respond. Optimism is fine; pretending nothing failed is not.