Checkboxes, Radio Buttons and Grouping
Checkboxes for many answers, radios for one. The name attribute is what groups radios, and fieldset with legend is what makes either group make sense.
-
HTML Basics
- What is HTML: The Structure Layer of Every Web Page
- HTML Document Structure: DOCTYPE, html, head and body
- Elements, Tags and Attributes: The Vocabulary of HTML
- HTML Comments: Notes That Ship With Your Code
- Block Level and Inline Elements
- Writing and Running Your First HTML Page
- How a Browser Turns Markup Into a Page
- Text and Formatting
- Links and Navigation
- Images and Media
- Lists
- Tables
-
Forms
- Form Structure: form, action and method
- Input Types: Text, Email, Number, Date and the Rest
- Labels: The Most Important Element in a Form
- Checkboxes, Radio Buttons and Grouping
- select, option, optgroup and datalist
- textarea, File Uploads and Hidden Fields
- Buttons: submit, reset and button
- Built In Form Validation
- GET or POST: What Happens When a Form Is Submitted
- Semantic HTML
- HTML5 Features
- Head and Metadata
- HTML with CSS
- HTML with JavaScript
- Accessibility
-
HTML SEO
- How Google Works: Crawling, Indexing and Ranking
- SEO Friendly HTML Structure
- Titles and Descriptions That Earn Clicks
- Headings and Content Structure for Search
- Internal Linking and Anchor Text
- robots.txt and XML Sitemaps
- Canonical URLs and Duplicate Content
- Structured Data and JSON-LD
- Image SEO
- Core Web Vitals and Mobile Friendliness
- DevTools and Debugging
- Editor Productivity
- HTML Best Practices
- HTML Projects
- Advanced Projects
- Practice and Exams
Concept
Two controls that look similar and behave completely differently.
- Checkbox - an independent on or off switch. Several can be checked. Each one is its own question.
- Radio button - one choice from a set. Checking one unchecks the others. The set is one question.
The rule of thumb: choose all that apply is checkboxes; choose one is radios.
Checkboxes
<fieldset>
<legend>Which updates would you like?</legend>
<label><input type="checkbox" name="topics" value="courses"> New courses</label>
<label><input type="checkbox" name="topics" value="events"> Events</label>
<label><input type="checkbox" name="topics" value="jobs" checked> Job postings</label>
</fieldset>Sharing a name across checkboxes is a convention for sending several values under one key. In PHP the name would be written topics[] to arrive as an array; other server languages differ. Independent checkboxes should each have their own name.
The unchecked checkbox problem
An unchecked checkbox sends nothing at all. Not false, not an empty string - the key simply is not present. Server code that reads the key directly will fail.
<!-- ensures a value always arrives -->
<input type="hidden" name="newsletter" value="no">
<label><input type="checkbox" name="newsletter" value="yes"> Subscribe</label>The hidden field comes first. If the box is checked, both are sent and the later value wins in most server frameworks. If not, only no arrives.
Radio buttons
<fieldset>
<legend>Preferred contact method</legend>
<label><input type="radio" name="contact" value="email" checked> Email</label>
<label><input type="radio" name="contact" value="phone"> Phone</label>
<label><input type="radio" name="contact" value="post"> Post</label>
</fieldset>The shared name is what makes them a group. Give two radios different names and both can be selected, which is the single most common radio button bug.
Radios are also unusual in that they cannot be unselected once a choice is made. If no answer is a valid state, either provide an explicit prefer not to say option or do not preselect anything.
Keyboard behaviour
Radios in a group form one tab stop. Tab moves into the group, arrow keys move between the options, and Tab moves out. This is correct and expected - do not try to make each radio individually tabbable.
Checkboxes are each their own tab stop, toggled with Space.
Why fieldset and legend are required here
Without a legend, a screen reader announces Email, radio button, one of three. The reader knows the options but not the question.
The legend supplies it: Preferred contact method, group. Email, radio button, one of three. For a radio or checkbox group this is not a nicety, it is what makes the group comprehensible.
<fieldset>
<legend>Do you need accommodation?</legend>
<label><input type="radio" name="accom" value="yes" required> Yes</label>
<label><input type="radio" name="accom" value="no"> No</label>
</fieldset>Note that required on any one radio in a group makes the whole group required. It only needs to be written once, though writing it on each does no harm.
The indeterminate state
A checkbox has a third visual state, used for a parent that controls several children where only some are checked. It is set only from JavaScript - there is no attribute for it.
<label><input type="checkbox" id="select-all"> Select all</label>document.getElementById("select-all").indeterminate = true;It is a display state only. The control still submits as checked or unchecked.
Styling
Native checkboxes and radios are hard to style and easy to break. The safe modern approach keeps the real control and restyles it:
input[type="checkbox"],
input[type="radio"] {
width: 1.15em;
height: 1.15em;
accent-color: #1e3a8a; /* recolours the native control */
}
/* a comfortable target the whole width of the text */
label:has(> input[type="checkbox"]) {
display: flex;
gap: 0.6rem;
align-items: center;
padding: 0.4rem 0;
cursor: pointer;
}accent-color is a one line way to match the brand without replacing the control. Hiding the real input and drawing a fake one with CSS works, but every time it is done the focus outline, the keyboard behaviour and the high contrast rendering have to be rebuilt by hand.
Important rules
- Radios are grouped by a shared
name, nothing else. - An unchecked checkbox or radio submits nothing.
checkedis a boolean attribute;checked="false"still checks it.- Without
value, a checked control submits the stringon, which is rarely what you want. - A radio group is one tab stop; arrow keys move within it.
requiredon one radio applies to the whole group.
Common mistakes
- Different
namevalues on radios that should be a group, letting several be selected. - Using radios where checkboxes are needed, so the reader cannot pick two.
- Omitting
valueand receivingonfor everything. - Reading an unchecked checkbox key on the server and getting an error.
- No
fieldsetandlegend, leaving the group without its question. - Hiding the native control with
display: none, which removes it from the tab order entirely. - Tiny tap targets on a phone.
Best practices
- Checkboxes for independent choices, radios for one from a set.
- Always wrap a group in a
fieldsetwith alegend. - Always give a
value. - Wrap the control in its label so the whole line is clickable.
- For yes or no questions with a default, prefer a single checkbox to two radios.
- Use
accent-colorbefore reaching for a custom control. - Keep radio lists under about seven options; beyond that use a
select.
Practice
- Build a radio group with four options and confirm it is one tab stop with arrow key movement.
- Give two radios different names and observe both being selectable.
- Submit a form with an unchecked checkbox and inspect what the server receives, then add the hidden field pattern.
- Style a checkbox group with
accent-colorand a full width clickable label.