HTMLCheckboxes & Radio Buttons

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

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>
Same name, multiple values
Giving each checkbox in a group the same 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

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>
Forgetting a shared name breaks the group
If each radio button in what should be one group has a different 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

name

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 name can be checked

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

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

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

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"
Always pair with a <label>
Wrapping the input in a <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 checked attribute 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

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

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

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;
}
Never hide the input with display:none or visibility:hidden
Fully hiding the native input removes it from keyboard focus and breaks screen reader interaction. Custom-styled checkbox implementations use CSS to visually hide only the default appearance (e.g. via 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

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>