The HTML
required
attribute forces a form field to be filled before the browser lets the form submit, but it only works on native, visible form controls inside a real
<form>
that submits the normal way. It quietly fails when the field is hidden, disabled, submitted with JavaScript, or when the input type does not support constraint validation. So if your required field lets an empty form through, the problem is almost always
where
or
how
the input lives, not the attribute itself.
Content Table
What the required attribute actually does
Adding
required
to an input tells the browser this field cannot be empty when the form is submitted. It is a boolean attribute, so its mere presence turns it on. You do not need a value.
<form action="/subscribe" method="post">
<label for="email">Email</label>
<input type="email" id="email" name="email" required>
<button type="submit">Subscribe</button>
</form>
When someone hits submit with that field empty, the browser blocks submission and shows a native bubble ("Please fill out this field"). This is part of the HTML5 constraint validation API, and it works with zero JavaScript. The exact wording and styling of the message comes from the browser, not your code, which is why it looks different in Chrome, Firefox and Safari.
The attribute also flips a CSS pseudo-class. Empty required fields match
:invalid, and filled ones match
:valid, so you can style them without touching JavaScript.
Why the required attribute fails
Most "the required attribute isn't working" bug reports trace back to one of these situations. The browser is behaving correctly in every case, it just is not validating the field you think it is.
| Situation | Why it fails |
|---|---|
Field is
disabled
|
Disabled controls are skipped by validation entirely and are not even sent to the server. |
Field is
hidden
|
type="hidden"
and CSS-hidden fields cannot be validated because the browser cannot focus them to show an error.
|
No wrapping
<form>
|
Constraint validation only runs on submit. No form, no submit, no check. |
| Submit via JavaScript |
Calling
form.submit()
bypasses validation completely. Only user-triggered or
requestSubmit()
submits validate.
|
novalidate
on the form
|
This attribute turns off all native validation for the entire form. |
Button has
formnovalidate
|
That specific submit button skips validation (common on "Save draft" buttons). |
| Whitespace-only input |
A single space counts as "filled".
required
checks for empty, not meaningful, content.
|
document.forms[0].submit(). That method never runs validation. Use
form.requestSubmit()
instead, which behaves like a real button click and honors
required.
The whitespace gap is worth calling out.
required
only guarantees the field is not empty, not that the value is sensible. A user typing one space passes. To catch that, pair it with a
pattern attribute for stricter validation
such as
pattern=".*\S.*"
to require at least one non-space character.
required
is only one of several validation types; see
HTML form validation
for the rest.
When the required attribute actually works
For
required
to reliably block empty submissions, all of these need to be true:
-
The control is a real form element (
input,select,textarea) inside a<form>. -
The field is visible and enabled (not
disabled, nottype="hidden"). -
The form is submitted by a genuine user action or
requestSubmit(), not rawsubmit(). -
Neither the form nor the clicked button carries
novalidate/formnovalidate. -
The input type supports validation (nearly all do, but
type="hidden",type="range",type="color", and buttons never fire it because they always have a value).
It works on more than plain text boxes. A required on a
textarea element for longer input
blocks empty messages, and on a
<select>
it forces a choice, as long as the default option has an empty value.
<select name="plan" required>
<option value="">Choose a plan</option>
<option value="free">Free</option>
<option value="pro">Pro</option>
</select>
If that first option had
value="free"
instead of an empty string, the select would always be "filled" and
required
would do nothing.
Required on checkboxes, radios and file inputs
These behave differently enough to catch people out:
-
Single checkbox:
requiredmeans the box must be checked. Perfect for "I agree to the terms". -
Radio group:
putting
requiredon any one radio in a group (samename) makes the whole group required, so the user must pick one. See accessible radio button patterns for the full markup. -
Checkbox group:
there is no native way to require "at least one of several".
requiredon a checkbox only requires that specific box. Multi-checkbox rules need JavaScript. -
File input:
requiredforces a file to be selected. Details and quirks live in this guide to the HTML file upload input.
Required vs aria-required
Native
required
already exposes the required state to screen readers, so you usually do not need anything else.
aria-required="true"
exists for cases where you cannot use the native attribute, for example a custom widget built from
div
s, or a field you deliberately validate yourself and do not want the browser blocking submission.
required
whenever possible. Reach for
aria-required
only on custom or JS-validated controls where
required
would either not apply or would fight your own logic. Never rely on
aria-required
alone to
enforce
anything, it only announces, it does not block submission.
One caveat:
aria-required
tells assistive tech the field is mandatory, but it does no validation on its own. If you use it, you are responsible for actually checking the value in JavaScript or on the server.
Marking required vs optional fields
Deciding between required vs optional fields is a design choice as much as a code one. A few practices that hold up well:
- Mark whichever is rarer. If most fields are required, label the few optional ones with "(optional)" instead of scattering asterisks everywhere.
-
Do not rely on color alone.
A red asterisk is invisible to colorblind users and screen readers. Use the native
requiredattribute plus visible text. - Ask for less. Every required field lowers completion rates. Cutting optional-but-required-looking fields is one of the reasons shorter forms get more submissions.
-
Validate on the server too.
Native validation is a convenience for users. Anyone can bypass it by editing HTML or sending a raw request, so treat
requiredas UX, not security.
That last point matters most. Client-side
required
improves the experience, but the real gate is your backend. For a broader picture of trustworthy submission handling, see how
form submission security
combines validation with CSRF protection and sanitization. And since validation only kicks in on submit, double-check where that submission goes with the guide to the
HTML form action attribute.
Build forms where the required attribute never silently fails
Our HTML forms guide walks through validation, submission handling and the exact markup that makes the HTML required attribute work every time, without the hidden-field and JavaScript-submit traps.
Read the HTML forms guide →
Most often the field is disabled, hidden, or the form is submitted with JavaScript's
form.submit()
, which bypasses validation. Check that the field is visible and enabled, the form has no
novalidate
attribute, and you use a real submit button or
requestSubmit()
.
No. Constraint validation only runs when a form is submitted. If your input sits outside a
<form>
element, there is no submit event to trigger the check, so
required
does nothing. Wrap the field in a form or validate manually with JavaScript.
Native
required
both announces the field to screen readers and blocks empty submission.
aria-required="true"
only announces it, doing no validation. Use native
required
whenever possible, and reserve
aria-required
for custom widgets or fields you validate yourself.
Not with native HTML. Adding
required
to a checkbox only requires that one box. For "pick at least one from several" you need JavaScript that checks the group on submit and sets a custom validity message, since the attribute has no group-level behavior for checkboxes.
No. Anyone can remove
required
in browser dev tools or send a raw request that skips it entirely. It is a user-experience helper, not a security control. Always re-check required fields on your server and combine that with proper input validation and CSRF protection.
