Skip to content
FormSubmit

HTML

HTML radio buttons: groups, yes/no, horizontal layout and JavaScript

How HTML form radio buttons work: grouping by name, default and required, yes/no questions, horizontal CSS, custom styling and getting the value in JavaScript.

5 min readUpdated Oct 9, 2026

HTML radio buttons are <input type="radio"> elements that share the same name, so only one in the group can be selected. Each needs its own value, which is what gets submitted. Wrap the group in a <fieldset> with a <legend> for accessibility, add checked for a default or required to force an answer, and read the choice in JavaScript with form.elements.name.value.

This guide covers building radio groups correctly, yes/no questions, horizontal layouts, custom styling and reading the value with JavaScript. It's part of the HTML form elements reference.

A radio button form

plan-form.html
<form action="https://formsubmit.app/f/YOUR_FORM_ID" method="POST">
  <fieldset>
    <legend>Which plan are you interested in?</legend>
    <label><input type="radio" name="plan" value="starter" checked> Starter</label>
    <label><input type="radio" name="plan" value="pro"> Pro</label>
    <label><input type="radio" name="plan" value="business"> Business</label>
  </fieldset>

  <label for="email">Email</label>
  <input id="email" type="email" name="email" autocomplete="email" required>

  <input type="text" name="_gotcha" tabindex="-1" autocomplete="off" style="display:none">
  <button type="submit">Send</button>
</form>

If someone picks Pro, the form submits plan=pro. The label text ("Pro") is only for people. The value ("pro") is what you receive.

How radio groups work

  • Same name, one group. Radio buttons with the same name in the same form form a group. Checking one unchecks the rest. A different name starts a new, independent group.
  • Every radio needs a value. Without one, the browser submits on, which tells you nothing about which option was picked.
  • Arrow keys move between options. The whole group is a single Tab stop, and the arrow keys change the selection. You get this for free with native radios.
  • Once selected, a group can't be cleared by clicking again. If "no answer" is valid, add it as an explicit option.

Default selection with checked

Add checked to the option that should be selected when the page loads. Only one radio per group should have it. A default is helpful when one answer is clearly the most common, but avoid it for questions where a pre-selected answer would bias the response, such as a rating.

Required radio groups

Add required to any one radio in the group, and the browser won't submit the form until one of the options is checked:

html
<label><input type="radio" name="size" value="s" required> Small</label>
<label><input type="radio" name="size" value="m"> Medium</label>
<label><input type="radio" name="size" value="l"> Large</label>

required has no effect when one option is already checked, because the group always has an answer.

Fieldset and legend for accessibility

Each radio has its own label ("Small"), but the question ("What size?") also needs to be read. Wrap the group in <fieldset> and put the question in <legend>. Screen readers then announce the legend when focus enters the group, for example "What size? Small, radio button, 1 of 3".

A heading or <p> above the radios isn't associated with them, so it isn't announced. The fieldset and legend guide covers styling the group so it doesn't look like a 1990s box.

Yes/no radio buttons

A yes/no question is a two-option radio group. Use clear values that read well in your inbox or spreadsheet:

yes-no.html
<fieldset>
  <legend>Have you used a form backend before?</legend>
  <label><input type="radio" name="used_before" value="yes" required> Yes</label>
  <label><input type="radio" name="used_before" value="no"> No</label>
</fieldset>

Why not a single checkbox? An unchecked checkbox sends nothing, so you can't tell "no" from "didn't answer". A required yes/no radio group always sends an explicit answer. For simple agreement, such as accepting terms, a single checkbox is still the right choice.

Horizontal radio buttons

Radios inside labels are inline by default, but they wrap awkwardly and the spacing is inconsistent. A flex row gives you control:

horizontal.html
<fieldset class="radio-row">
  <legend>Preferred contact method</legend>
  <label><input type="radio" name="contact_method" value="email" checked> Email</label>
  <label><input type="radio" name="contact_method" value="phone"> Phone</label>
  <label><input type="radio" name="contact_method" value="whatsapp"> WhatsApp</label>
</fieldset>

<style>
  .radio-row {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem 1.5rem;
    border: 0;
    padding: 0;
    margin: 0;
    min-width: 0;
  }
  .radio-row legend {
    flex-basis: 100%;
    padding: 0;
    margin-bottom: 0.5rem;
  }
  .radio-row label {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
  }
</style>

flex-wrap: wrap lets the options stack on narrow screens instead of overflowing. For a vertical list, use flex-direction: column.

Custom radio button styling

accent-color

The simplest change is accent-color, which recolours the native control while keeping its behaviour and accessibility:

css
input[type="radio"] {
  accent-color: #4f46e5;
  width: 1.125rem;
  height: 1.125rem;
}

A fully custom radio with appearance: none

For full control, remove the native look with appearance: none and draw it yourself. The input stays a real radio, so keyboard support, required and form submission still work:

custom-radio.css
input[type="radio"] {
  appearance: none;
  width: 1.125rem;
  height: 1.125rem;
  margin: 0;
  border: 2px solid #6b7280;
  border-radius: 50%;
  display: inline-grid;
  place-content: center;
}
input[type="radio"]::before {
  content: "";
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: #4f46e5;
  transform: scale(0);
  transition: transform 120ms ease;
}
input[type="radio"]:checked {
  border-color: #4f46e5;
}
input[type="radio"]:checked::before {
  transform: scale(1);
}
input[type="radio"]:focus-visible {
  outline: 2px solid #4f46e5;
  outline-offset: 2px;
}

Avoid hiding the input with display: none and styling a <span> instead. That removes it from keyboard navigation and from the accessibility tree.

Get the selected radio value in JavaScript

There are three common ways. All assume the form above.

radio-value.js
const form = document.querySelector("form");

// 1. RadioNodeList: the simplest. Returns "" if nothing is checked.
const plan = form.elements.plan.value;

// 2. The :checked selector. Returns null if nothing is checked.
const checked = form.querySelector('input[name="plan"]:checked');
const plan2 = checked ? checked.value : null;

// 3. FormData: what would actually be submitted. Returns null if nothing is checked.
const plan3 = new FormData(form).get("plan");

To react when the selection changes, listen for change on the form, since the event bubbles:

js
form.addEventListener("change", (event) => {
  if (event.target.name === "plan") {
    console.log("Selected plan:", event.target.value);
  }
});

You can also set the selection: form.elements.plan.value = "pro" checks the radio whose value is pro.

What is submitted when none is selected

If no radio in a group is checked, the group's name is left out of the submission completely. It isn't sent as an empty string. On the receiving end, the field simply doesn't exist. If you need to know that someone skipped the question, make the group required, or add an explicit option such as "Prefer not to say".

Radio vs checkbox vs select

UseWhen
Radio buttonsOne answer from 2 to about 6 options, where seeing every option helps.
CheckboxesAny number of answers, including none, or a single on/off choice.
Select dropdownOne answer from a long list, such as a country, or when space is tight.

Sending radio button answers

A radio group's answer arrives as an ordinary field, such as plan: pro, alongside the rest of the form. Point the form's action at https://formsubmit.app/f/YOUR_FORM_ID with method="POST" and each submission is stored in your dashboard and emailed to you, with spam filtered out. See how to send an HTML form to email for the full setup, or go back to the HTML form elements overview.

Frequently asked questions

How do I group radio buttons?

Give them the same name attribute. Radio buttons with the same name inside the same form act as one group, so checking one unchecks the others.

How do I make a radio button group required?

Add the required attribute to at least one radio button in the group. The browser then blocks submission until any option in that group is checked. Adding it to every radio in the group is also fine.

What is submitted if no radio button is selected?

Nothing. The group's name is left out of the submission entirely, not sent as an empty value. Use a default checked option or required if you always need an answer.

How do I get the selected radio button value in JavaScript?

Use form.elements.groupName.value, which returns the checked radio's value or an empty string. You can also use document.querySelector with the :checked selector, or new FormData(form).get(name).

How do I display radio buttons horizontally?

Put each radio and its text inside a label, then make the container a flex row with display flex, flex-wrap wrap and a gap.

Should I use radio buttons or a select dropdown?

Use radio buttons for two to about six options so every choice is visible at once. Use a select for longer lists, and checkboxes when more than one answer is allowed.

Keep reading

Your form backend is 60 seconds away

Sign up with Google or email, create a form, paste the endpoint. Free forever for small sites — no credit card.