HTML Guides for required
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 HTML specification enforces this rule because a required <select> element needs options for the user to choose from. Without any <option> children, the element is semantically meaningless — it's a dropdown with nothing to select, yet the form demands a selection before submission. This creates an impossible situation for the user and an ambiguous state for the browser.
This rule specifically applies when all three of these conditions are true:
- The
requiredattribute is present. - The
multipleattribute is not present. - The
sizeattribute is either absent or set to1(the default for a single-selection<select>).
When multiple is set or size is greater than 1, the <select> behaves differently (as a list box rather than a dropdown), and the specification relaxes this constraint. But for the standard single-selection dropdown, at least one <option> is mandatory.
Why this matters
- Usability: A required dropdown with no options gives users no way to satisfy the form requirement, effectively blocking form submission entirely.
- Accessibility: Screen readers announce
<select>elements along with their available options. An empty required dropdown creates a confusing experience for assistive technology users. - Form validation: Browsers use the first
<option>with an emptyvalueas the placeholder. The built-in constraint validation forrequiredselects relies on checking whether the selected option's value is a non-empty string. Without any options, this validation behavior is undefined.
How the placeholder pattern works
The HTML specification defines a specific behavior for required single-selection dropdowns: the first <option> element, if it has an empty value attribute, acts as a placeholder. When the form is submitted with this placeholder still selected, browser validation will reject the submission because the value is empty. This is the standard pattern for prompting users to make a deliberate choice.
Examples
❌ Invalid: required <select> with no options
<label for="color">Pick a color:</label>
<select id="color" name="color" required>
</select>
This triggers the validation error because there are no <option> elements inside the required <select>.
❌ Invalid: required <select> with only a group but no options
<label for="color">Pick a color:</label>
<select id="color" name="color" required>
<optgroup label="Colors">
</optgroup>
</select>
An empty <optgroup> doesn't satisfy the requirement. The <select> still needs at least one <option>.
✅ Valid: required <select> with a placeholder and options
<label for="color">Pick a color:</label>
<select id="color" name="color" required>
<option value="">--Select a color--</option>
<option value="red">Red</option>
<option value="green">Green</option>
<option value="blue">Blue</option>
</select>
The first <option> has an empty value, so it serves as a placeholder. The browser will require the user to choose one of the other options before submitting the form.
✅ Valid: required <select> with multiple (rule does not apply)
<label for="colors">Pick one or more colors:</label>
<select id="colors" name="colors" required multiple>
</select>
This does not trigger the error because the multiple attribute is present, which exempts the element from this particular rule. However, an empty multi-select is still poor UX and should generally be avoided.
✅ Valid: required <select> with size greater than 1 (rule does not apply)
<label for="colors">Pick a color:</label>
<select id="colors" name="colors" required size="4">
</select>
When size is greater than 1, the element renders as a list box and the rule no longer applies. Again, while technically valid, an empty list box isn't useful in practice.
✅ Valid: required <select> with grouped options
<label for="vehicle">Choose a vehicle:</label>
<select id="vehicle" name="vehicle" required>
<option value="">--Select a vehicle--</option>
<optgroup label="Cars">
<option value="sedan">Sedan</option>
<option value="suv">SUV</option>
</optgroup>
<optgroup label="Trucks">
<option value="pickup">Pickup</option>
<option value="semi">Semi</option>
</optgroup>
</select>
Options inside <optgroup> elements count as child options of the <select>, so this is fully valid.
The HTML required attribute was introduced in HTML5 and tells both the browser and assistive technologies that a form field must be filled in before the form can be submitted. The aria-required attribute serves the same purpose but comes from the WAI-ARIA specification, which was designed to fill accessibility gaps in HTML. Now that required is widely supported, using both attributes on the same element is unnecessary duplication.
The W3C validator raises this warning because redundant ARIA attributes add noise to your markup without providing any benefit. One of the core principles of ARIA usage is the first rule of ARIA: if you can use a native HTML element or attribute that already has the semantics you need, use that instead of adding ARIA. The native required attribute provides built-in browser validation, visual cues, and accessibility information all at once — something aria-required alone cannot do.
Modern screen readers such as NVDA, JAWS, and VoiceOver all correctly interpret the native required attribute and announce the field as required to users. Keeping both attributes doesn't cause a functional problem, but it creates maintenance overhead, clutters your code, and signals to other developers that something special might be going on when it isn't.
How to fix it
- If your element already has the
requiredattribute, removearia-required="true". - If your element only has
aria-required="true"and you want browser-native validation, replace it withrequired. - In rare cases where you need to support assistive technologies that don't recognize the native
requiredattribute (some very old screen reader versions), keeping both is a conscious trade-off — but for the vast majority of projects, the native attribute alone is sufficient.
Examples
❌ Redundant aria-required alongside required
<form action="/order">
<label for="city">City</label>
<input id="city" name="city" type="text" aria-required="true" required>
<label for="email">Email</label>
<input id="email" name="email" type="email" aria-required="true" required>
<label for="comments">Comments</label>
<textarea id="comments" name="comments" aria-required="true" required></textarea>
<button type="submit">Submit</button>
</form>
This triggers the validator warning on every element where both attributes appear.
✅ Using the native required attribute only
<form action="/order">
<label for="city">City</label>
<input id="city" name="city" type="text" required>
<label for="email">Email</label>
<input id="email" name="email" type="email" required>
<label for="comments">Comments</label>
<textarea id="comments" name="comments" required></textarea>
<button type="submit">Submit</button>
</form>
✅ Using aria-required on a non-native element
There are valid use cases for aria-required — specifically when you build custom form controls that don't use native form elements. In that scenario, aria-required is the correct choice because the native required attribute has no effect on non-form elements.
<div role="combobox" aria-required="true" aria-expanded="false" aria-labelledby="color-label">
<span id="color-label">Favorite color</span>
</div>
Here, aria-required="true" is necessary because a <div> doesn't support the native required attribute.
A field with the required attribute has an aria-required value that doesn't match it: remove aria-required and keep the native attribute.
aria-required only accepts true or false. A value such as yes, 1 or required is neither, so the validator reports two errors on the same field: a Bad value error for aria-required, and this one, because the value differs from what required states. These values usually come from copying the native attribute into the ARIA one, as in aria-required="required", or from a template that prints a boolean as 1 or True.
The required attribute already tells assistive technologies that the field must be filled in, and it turns on the browser's own form validation. The field doesn't need aria-required at all, so remove it. If you're building a custom widget that can't take required, such as an element with role="combobox", write aria-required as exactly true or false.
Other values give different messages. aria-required="false" next to required is its own error, because it contradicts the native attribute. aria-required="true", or a value that exactly repeats the value of required (such as required="required" aria-required="required"), only gets a warning that the attribute is unnecessary.
Invalid example
<label for="email">Email</label>
<input type="email" id="email" name="email" required aria-required="yes">
Valid example
<label for="email">Email</label>
<input type="email" id="email" name="email" required>
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.
required is a boolean attribute, so on <input>, <select> and <textarea> you write it bare, empty or as required="required", and a value like "true" or "false" is an error.
The HTML standard allows two values for a boolean attribute: the empty string and the attribute's own name, in any letter case. So required, required="", required="required" and required="REQUIRED" all pass. The validator reports any other value with this message and quotes what it found: "true", "false", "1", "yes", and also "required " with a trailing space.
Browsers don't read the value at all. If the attribute is there, the field is mandatory, so required="false" blocks the form just like required="true" does. To make a field optional, remove the attribute.
The bad value usually comes from a form builder or template that writes a boolean setting straight into the markup, often with aria-required="true" next to it. Once you fix required, the validator warns that aria-required is unnecessary on an element that has required, so remove it too. From JavaScript, set the property (field.required = false) or call removeAttribute("required"). Calling setAttribute("required", "false") leaves the field required.
Some details depend on the element:
<input>:requiredonly applies to types a user can leave empty or unchecked:text,search,email,url,tel,password,number, the date and time types,checkbox,radioandfile. Onhidden,range,colorand the button types (submit,reset,button,image), it isn't allowed at all, and the validator says so in a separate error. Remove it there instead of fixing the value.<textarea>: a required text area blocks the form while its value is empty. The text between the opening and closing tags is the starting value, so spaces a template adds for indentation make the field count as filled in before anyone types. Put</textarea>right after the opening tag.<select>: a required drop-down (nomultiple, and nosizeabove1) needs a placeholder as its first<option>, withvalue=""and directly inside the<select>, not in an<optgroup>. An option without avalueattribute uses its text as its value, so<option>Choose a size</option>counts as an answer, and the form submits "Choose a size" if the user never opens the list. When the first option isn't a valid placeholder, the validator reports a second error about it, even whilerequiredhas a bad value.
Invalid example
<form action="/order" method="post">
<label for="email">Email</label>
<input type="email" id="email" name="email" required="true">
<label for="size">Size</label>
<select id="size" name="size" required="true">
<option value="">Choose a size</option>
<option value="s">Small</option>
<option value="m">Medium</option>
<option value="l">Large</option>
</select>
<label for="notes">Notes (optional)</label>
<textarea id="notes" name="notes" rows="3" required="false"></textarea>
<button type="submit">Place order</button>
</form>
Valid example
<form action="/order" method="post">
<label for="email">Email</label>
<input type="email" id="email" name="email" required>
<label for="size">Size</label>
<select id="size" name="size" required>
<option value="">Choose a size</option>
<option value="s">Small</option>
<option value="m">Medium</option>
<option value="l">Large</option>
</select>
<label for="notes">Notes (optional)</label>
<textarea id="notes" name="notes" rows="3"></textarea>
<button type="submit">Place order</button>
</form>
A required <select> drop-down must start with a placeholder <option> whose value is empty, so the browser can tell when the user hasn't picked anything.
A <select> with no multiple attribute and no size greater than 1 renders as a drop-down, and the browser selects its first option by default. For required to block an untouched drop-down, that first option has to mean "no choice yet". HTML calls it the placeholder label option, and it only counts as one when its value is the empty string.
An option's value is its value attribute or, if it has none, its text. Both <option value="none">Select a topic</option> and <option>Select a topic</option> have a non-empty value, so the browser accepts the prompt as a real answer. The form submits even if the user never opens the drop-down, and the server receives none or Select a topic as the chosen topic.
Give the first option value="" and keep the prompt as its text. An empty <option></option> also passes this check, but the validator then asks for a label attribute, so a text prompt is simpler. If you want a list box that shows every option at once instead of a drop-down, set size to the number of options, and the validator stops asking for a placeholder.
Invalid example
<label for="topic">Topic</label>
<select id="topic" name="topic" required>
<option value="none">Select a topic</option>
<option value="billing">Billing</option>
<option value="support">Technical support</option>
</select>
Valid example
<label for="topic">Topic</label>
<select id="topic" name="topic" required>
<option value="">Select a topic</option>
<option value="billing">Billing</option>
<option value="support">Technical support</option>
</select>
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