required

Prevents form submission when a field is empty. Integrates with constraint validation, CSS pseudo-classes, and screen reader announcements.

Overview

The required attribute prevents form submission when a field is empty. The browser checks the constraint on submit and shows a native error message if the field has no value.

This is the foundation of client-side form validation. It works without JavaScript, integrates with CSS pseudo-classes for styling, and is announced by screen readers.

Applies to: <input>, <select>, <textarea>

Values

ElementWhat "empty" means
Text inputValue is an empty string
<textarea>Value is an empty string
<select>Selected option has value=""
CheckboxNot checked
Radio groupNo radio in the group is selected
File inputNo file selected
<form class="stacked"> <label for="name">Full Name <span aria-hidden="true">*</span></label> <input type="text" id="name" name="name" required /> <label for="email">Email <span aria-hidden="true">*</span></label> <input type="email" id="email" name="email" required /> <label for="bio">Bio (optional)</label> <textarea id="bio" name="bio" rows="3"></textarea> <button type="submit">Submit</button> </form>

Select Elements

For <select required>, the first option must have an empty value attribute. This serves as the placeholder. The browser considers the field invalid as long as the empty-value option is selected.

<label for="country">Country <span aria-hidden="true">*</span></label> <select id="country" name="country" required> <option value="">-- Select a country --</option> <option value="US">United States</option> <option value="CA">Canada</option> <option value="GB">United Kingdom</option> </select>

Radio Groups

Adding required to any radio button in a group makes the entire group required — at least one radio must be selected. You only need required on one radio, but adding it to the first one is a common convention for readability.

<fieldset> <legend>Subscription Plan <span aria-hidden="true">*</span></legend> <label> <input type="radio" name="plan" value="free" required /> Free </label> <label> <input type="radio" name="plan" value="pro" /> Pro </label> <label> <input type="radio" name="plan" value="enterprise" /> Enterprise </label> </fieldset>

Checkboxes

A required checkbox must be checked for the form to submit. This is the standard pattern for "I agree to the terms" checkboxes.

<form class="stacked"> <label> <input type="checkbox" name="terms" required /> I agree to the Terms of Service <span aria-hidden="true">*</span> </label> <button type="submit">Create Account</button> </form>

CSS Pseudo-Classes

The required attribute activates several CSS pseudo-classes for validation styling.

Pseudo-classMatches when
:requiredField has the required attribute
:optionalField does not have required
:validField satisfies all constraints
:invalidField violates a constraint (including required)
:user-invalidInvalid after user has interacted with the field
/* Visual indicator for required fields */ input:required, select:required, textarea:required { border-left: 3px solid var(--color-primary); } /* Valid required field */ input:required:valid { border-left-color: var(--color-success); } /* Invalid after user interaction */ input:required:user-invalid { border-left-color: var(--color-danger); } /* Optional fields get no special treatment */ input:optional { border-left: 3px solid transparent; }

Prefer :user-invalid over :invalid. The :invalid pseudo-class applies immediately on page load, which means empty required fields show error styles before the user has done anything. The :user-invalid pseudo-class waits until the user has interacted with the field.

Custom Validation Messages

Native validation messages are functional but generic. Use setCustomValidity() to provide context-specific messages.

const email = document.querySelector('#email'); email.addEventListener('input', () => { if (email.validity.valueMissing) { email.setCustomValidity('We need your email to send the confirmation.'); } else if (email.validity.typeMismatch) { email.setCustomValidity('This does not look like an email address.'); } else { email.setCustomValidity(''); // Clear — field is valid } });

Call setCustomValidity('') (empty string) to mark the field as valid. Forgetting this step is a common bug — the field stays invalid even after the user corrects the value.

Bypassing Validation

Use formnovalidate on a submit button to bypass all constraint validation for that specific submission. This is ideal for "Save Draft" buttons where incomplete data is acceptable.

<form class="stacked"> <label for="draft-title">Title</label> <input type="text" id="draft-title" name="title" required /> <label for="draft-body">Body</label> <textarea id="draft-body" name="body" rows="4" required></textarea> <footer class="actions end"> <!-- This button validates --> <button type="submit">Publish</button> <!-- This button skips validation --> <button type="submit" formnovalidate>Save Draft</button> </footer> </form>

See novalidate for more on validation bypass patterns.

Accessibility

  • Screen readers announce required fields as "required". You do not need aria-required="true" when the native required attribute is present — it is redundant.
  • Always pair the required attribute with a visible indicator (like an asterisk *) so sighted users can identify required fields without submitting first.
  • Use aria-hidden="true" on decorative asterisks so screen readers do not announce "star" alongside "required".
  • Native validation messages are automatically announced by screen readers when the form is submitted with invalid fields.

Limitations

  • required is a boolean attribute. required="false" still makes the field required. Remove the attribute entirely to make it optional.
  • Constraint validation does not run on disabled or readonly fields, even if they have the required attribute.
  • Validation only runs on form submit (or when you call checkValidity() / reportValidity() in JavaScript). Typing in a field does not trigger it.
  • The novalidate attribute on the form or formnovalidate on a button bypasses all constraint validation, including required.
  • Native validation tooltips cannot be styled with CSS. If you need custom styling, use novalidate on the form and build your own validation UI.

See Also

  • pattern — regex-based validation
  • novalidate — bypass validation per form or per button
  • disabled — disabling skips validation entirely
  • <form> element reference
  • <input> element reference