HTML Guides for radio
Learn how to identify and fix common HTML validation errors flagged by the W3C Validator — so your pages are standards-compliant and render correctly across every browser. Also check our Accessibility Guides.
The required attribute is a boolean attribute that tells the browser a field must be filled in before the form can be submitted. However, not every input type supports this concept. Some input types always have a value (like range, which defaults to a midpoint, or color, which defaults to #000000), while others represent actions rather than user data (like submit, reset, image, and button). For hidden inputs, the user has no way to interact with the field at all, so requiring them to provide a value makes no sense.
The HTML specification explicitly limits required to the following input types: checkbox, date, datetime-local, email, file, month, number, password, radio, search, tel, text, time, url, and week.
Using required on an unsupported type is invalid HTML. Browsers will typically ignore the attribute in this situation, which means you might believe a field is required when it actually isn't being validated at all. This can lead to forms being submitted with missing or unexpected data. It also creates confusion for assistive technologies — screen readers may announce a field as required even though the browser won't enforce it, misleading users.
How to fix it
- Check the input type. If you're using
requiredon an input with a type likehidden,range,color,submit,reset,image, orbutton, the attribute is not allowed. - Remove the
requiredattribute if the input type inherently provides a value or doesn't accept user-provided data. - Change the input type if you actually need the field to be required and the current type doesn't match your intent.
- Use server-side validation for inputs like
hiddenthat can't userequiredbut still need a value.
Examples
❌ Invalid: required on a hidden input
<form>
<input type="hidden" name="token" required>
<button type="submit">Submit</button>
</form>
The user cannot interact with a hidden input, so required is not allowed here. The browser won't enforce it.
❌ Invalid: required on a range input
<form>
<label for="volume">Volume:</label>
<input type="range" id="volume" name="volume" min="0" max="100" required>
<button type="submit">Submit</button>
</form>
A range input always has a value (it defaults to the midpoint), so required is meaningless and not permitted.
❌ Invalid: required on a color input
<form>
<label for="color">Pick a color:</label>
<input type="color" id="color" name="color" required>
<button type="submit">Submit</button>
</form>
A color input always has a value (defaulting to #000000), so required is not valid here.
✅ Valid: required removed from unsupported types
<form>
<input type="hidden" name="token" value="abc123">
<label for="volume">Volume:</label>
<input type="range" id="volume" name="volume" min="0" max="100">
<button type="submit">Submit</button>
</form>
✅ Valid: required on supported input types
<form>
<label for="email">Email:</label>
<input type="email" id="email" name="email" required>
<label for="dob">Date of birth:</label>
<input type="date" id="dob" name="dob" required>
<label>
<input type="checkbox" name="terms" required>
I agree to the terms
</label>
<button type="submit">Submit</button>
</form>
These input types — email, date, and checkbox — all accept direct user input and are on the allowed list for the required attribute.
The aria-checked attribute is redundant on <input type="radio"> because the browser already exposes the checked state to assistive technologies through the native checked property.
Radio inputs have built-in semantics that map directly to the aria-checked state. When a radio button is selected, the browser automatically communicates that state to the accessibility tree. Adding aria-checked manually creates a conflict: the attribute could fall out of sync with the actual checked state, and it overrides the native semantics that assistive technologies already understand.
The ARIA in HTML specification explicitly prohibits aria-checked on <input type="radio">. This falls under the general principle of not using ARIA attributes to duplicate what HTML already provides natively.
If you need to create custom styled radio buttons that don't use native <input> elements, then aria-checked belongs on an element with role="radio". But when using a standard <input type="radio">, the checked attribute (or the DOM property) is all you need.
Invalid example
<label>
<input type="radio" name="color" value="red" aria-checked="true" checked>
Red
</label>
<label>
<input type="radio" name="color" value="blue" aria-checked="false">
Blue
</label>
Valid example
Remove aria-checked and rely on the native checked attribute:
<label>
<input type="radio" name="color" value="red" checked>
Red
</label>
<label>
<input type="radio" name="color" value="blue">
Blue
</label>
If you need a custom radio group without native inputs, use role="radio" with aria-checked:
<div role="radiogroup" aria-label="Color">
<span role="radio" aria-checked="true" tabindex="0">Red</span>
<span role="radio" aria-checked="false" tabindex="-1">Blue</span>
</div>
The aria-invalid attribute belongs on the role="radiogroup" element that wraps the options, not on each role="radio" option inside it.
WAI-ARIA 1.2 deprecated aria-invalid as a global state, and future versions will only allow it on the roles that support it: application, checkbox, combobox, gridcell, listbox, radiogroup, slider, spinbutton, textbox and tree, plus the roles that inherit from them. radio isn't on that list. A radio button's validity depends on the whole group. A required choice is either made or missing, and no single option is wrong by itself.
Browsers and screen readers aren't required to expose a state on a role that doesn't support it, so an error set on the options may never reach the user.
The validator flags any element with an explicit role="radio" and an aria-invalid attribute, whatever its value, so aria-invalid="false" triggers the warning too. Native <input type="radio"> elements aren't flagged. To fix it, remove the attribute from every option and set it on the radiogroup container. Point aria-describedby on that container at the error message, so screen readers announce it along with the group's label.
Invalid example
<p id="plan-label">Choose a plan</p>
<div role="radiogroup" aria-labelledby="plan-label">
<div role="radio" aria-checked="false" aria-invalid="true" tabindex="0">Basic</div>
<div role="radio" aria-checked="false" aria-invalid="true" tabindex="-1">Pro</div>
</div>
<p id="plan-error">Select a plan to continue.</p>
Valid example
<p id="plan-label">Choose a plan</p>
<div role="radiogroup" aria-labelledby="plan-label" aria-invalid="true" aria-describedby="plan-error">
<div role="radio" aria-checked="false" tabindex="0">Basic</div>
<div role="radio" aria-checked="false" tabindex="-1">Pro</div>
</div>
<p id="plan-error">Select a plan to continue.</p>
The role="radio" attribute is redundant on an <input type="radio"> element because the browser already exposes this element with the radio role to assistive technologies.
Screen readers and other assistive tools determine an element's purpose through its implicit ARIA role. The <input type="radio"> element has an implicit role of radio as defined in the ARIA in HTML specification. Adding role="radio" explicitly just repeats what the browser already communicates, and the W3C validator flags this as unnecessary.
Redundant roles add clutter to your markup without any accessibility benefit. In some edge cases, explicitly setting a role that matches the implicit one can even cause unexpected behavior in certain browser and screen reader combinations. The general rule: don't set a role on an element that already has that same role by default.
This applies to many other elements too. For example, <button role="button">, <a href="..." role="link">, and <nav role="navigation"> are all similarly redundant.
HTML examples
Before: redundant role
<label>
<input type="radio" name="color" value="red" role="radio">
Red
</label>
<label>
<input type="radio" name="color" value="blue" role="radio">
Blue
</label>
After: role removed
<label>
<input type="radio" name="color" value="red">
Red
</label>
<label>
<input type="radio" name="color" value="blue">
Blue
</label>
Remove the role="radio" attribute. The element already communicates its role to assistive technologies without it.
Validate at scale.
Ship accessible websites, faster.
Automated HTML & accessibility validation for large sites. Check thousands of pages against WCAG guidelines and W3C standards in minutes, not days.
1K Weekly
1,000 monthly checks. Cancel anytime.
Get 1K Weekly →Join teams across 40+ countries