Checkboxes and Radio Buttons
Checkboxes and radio buttons both let users pick from a set of options, but they answer different questions. A checkbox asks "is this on or off?" — each one is independent. A radio button asks "which one of this group?" — only one can be selected at a time.
Checkboxes: Multi-Select
<input type="checkbox"> represents an independent on/off toggle. Multiple checkboxes in the same form are unrelated to each other unless you write logic that connects them — a user can check any combination, including none or all of them.
checkboxes.html
<fieldset> <legend>Choose your toppings</legend> <label><input type="checkbox" name="toppings" value="cheese"> Cheese</label> <label><input type="checkbox" name="toppings" value="mushrooms"> Mushrooms</label> <label><input type="checkbox" name="toppings" value="olives"> Olives</label> </fieldset>
name (here, toppings) lets the server receive every checked value under that one field name when the form submits — commonly as an array, depending on your backend framework.Radio Buttons: Single-Select From a Group
<input type="radio"> represents one option in a mutually exclusive set. Radio buttons only work as a group when they share the same name attribute — that shared name is what tells the browser "these buttons belong together, so selecting one deselects the others."
radio-group.html
<fieldset> <legend>Choose your delivery size</legend> <label><input type="radio" name="size" value="small"> Small</label> <label><input type="radio" name="size" value="medium"> Medium</label> <label><input type="radio" name="size" value="large"> Large</label> </fieldset>
name, the browser treats them as independent controls — a user could end up with "small" and "large" both selected, which defeats the entire purpose of radio buttons.Attribute | Checkbox | Radio |
|---|---|---|
| Groups values submitted together, but selection is independent per checkbox | Groups buttons into a mutually exclusive set |
Selection rule | Any number can be checked, including zero | Exactly one per shared |
Typical use | "Select all that apply" | "Select exactly one" |
The checked Attribute
Add the boolean checked attribute to pre-select a checkbox or radio button when the page loads. For a radio group, only one option should have checked — if more than one does, browsers typically honor only the last one, which is confusing and best avoided.
checked-default.html
<label><input type="checkbox" name="newsletter" checked> Subscribe to newsletter</label> <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> </fieldset>
The Indeterminate State (JavaScript Only)
Checkboxes support a third visual state — indeterminate — typically used for a "select all" checkbox that represents a parent of a partially-checked group. Unlike checked, there is no HTML attribute for indeterminate; it can only be set through the DOM with JavaScript, and it's purely visual — it doesn't affect what value gets submitted with the form.
indeterminate.html
<label><input type="checkbox" id="select-all"> Select all</label> <label><input type="checkbox" class="item" checked> Item 1</label> <label><input type="checkbox" class="item"> Item 2</label> <label><input type="checkbox" class="item" checked> Item 3</label>
indeterminate.js
const selectAll = document.getElementById('select-all');
const items = document.querySelectorAll('.item');
const checkedCount = [...items].filter((el) => el.checked).length;
if (checkedCount === 0) {
selectAll.checked = false;
selectAll.indeterminate = false;
} else if (checkedCount === items.length) {
selectAll.checked = true;
selectAll.indeterminate = false;
} else {
selectAll.indeterminate = true;
}// selectAll.indeterminate = true renders a dash (-) in the box // instead of a checkmark, signaling "some, but not all, are checked"
<label> (or connecting one via for/id) makes the whole label text clickable and gives screen reader users an accessible name — never rely on placeholder text or surrounding prose alone.Use checkboxes when zero, one, or many options can be true at once.
Use radio buttons when exactly one option from a group must be selected — and always give them the same
name.The
checkedattribute sets the initial state; only one radio per group should have it.Indeterminate is a JavaScript-only visual state for representing a partially-checked group — it is not an HTML attribute.
A Single Standalone Checkbox (Boolean Toggle)
Not every checkbox belongs to a group — a single checkbox is a perfectly normal way to represent one independent yes/no setting, like agreeing to terms or subscribing to a mailing list.
single-checkbox.html
<label> <input type="checkbox" name="agree-terms" required> I agree to the Terms of Service </label>
Reading Values With JavaScript
checked as a DOM property (not just an HTML attribute) reflects live state and can be read or set programmatically. For a group of checkboxes sharing a name, collect the checked ones by querying the group.
read-checkbox-values.js
const form = document.querySelector('form');
form.addEventListener('submit', (event) => {
const toppings = [...form.querySelectorAll('input[name="toppings"]:checked')]
.map((el) => el.value);
console.log(toppings); // e.g. ["cheese", "olives"]
});Styling Checkboxes and Radios
Native checkbox/radio styling is famously hard to customize consistently across browsers. A common modern approach visually hides the native input (while keeping it functional and accessible) and draws a custom control next to it using CSS, keyed off the :checked pseudo-class.
custom-checkbox.css
input[type="checkbox"] {
appearance: none;
width: 20px;
height: 20px;
border: 2px solid #888;
border-radius: 4px;
}
input[type="checkbox"]:checked {
background-color: #3366ff;
border-color: #3366ff;
}appearance: none or a clip-path/opacity technique) while keeping the real input focusable and operable.required on Checkboxes and Radios
Adding required to a single checkbox forces it to be checked before the form submits (common for terms-of-service agreements). Adding required to any radio button in a group requires that some option in that group be selected — it doesn't need to be on every button, just present.
required-radio-group.html
<fieldset> <legend>Preferred contact method</legend> <label><input type="radio" name="contact" value="email" required> Email</label> <label><input type="radio" name="contact" value="phone"> Phone</label> </fieldset>