The required attribute.
Validation without JavaScript.
One attribute and the browser enforces the check for you. When a form is submitted, the browser validates every field with required and blocks submission if any are empty. No JavaScript, no library, no server round-trip. This page covers what it does, what it doesn't, and the pattern/minlength combo that covers the rest of the validation you'd otherwise write by hand.
Short answer: Add required to any <input>, <select>, or <textarea>. The browser blocks form submission until it has a value. Combine with type="email" for email format, minlength / maxlength for length, and pattern for a custom regex. The attribute is a UX check, not a security check — always validate on the server too.
✅ How it works
The native check, on submit only.
Fires on submit
The check runs when the form is submitted, not on every keystroke. Blur and change don't trigger the required error.
Blocks submission
The form never navigates. The browser scrolls to the first invalid field and shows a native bubble.
Works with select and radio
<select required> requires a non-empty option. <input type="radio" required> requires one in the group to be checked.
novalidate disables it
Adding novalidate to the form turns off native validation entirely. Use it only when you validate in JS.
✅ Before and after
The same form, with and without validation.
<form action="/submit" method="POST"> <label for="email">Email</label> <input id="email" name="email" type="email"> <button type="submit">Subscribe</button> </form>
❌ Empty email submits successfully. ❌ Server receives email="" and must reject it. ❌ Extra round-trip, worse UX.
<form action="/submit" method="POST"> <label for="email">Email</label> <input id="email" name="email" type="email" required> <button type="submit">Subscribe</button> </form>
✅ Empty email blocks submission. ✅ Browser shows "Please fill out this field". ✅ Focus moves to the email field automatically. ✅ No server round-trip needed.
✅ Combining with other validators
required checks presence. Add more attributes for format.
<form action="/signup" method="POST">
<input name="email" type="email" required>
<input name="password" type="password" required minlength="8">
<input name="username" type="text" required
pattern="[a-zA-Z0-9_]{3,20}"
title="3–20 characters: letters, numbers, underscore">
<input name="age" type="number" required min="18" max="120">
<input name="terms" type="checkbox" required>
<select name="country" required>
<option value="">Choose…</option>
<option value="us">United States</option>
<option value="uk">United Kingdom</option>
</select>
<button type="submit">Sign up</button>
</form>
required → must have a value type="email" → must look like email (user@domain) minlength="8" → at least 8 characters pattern="..." → must match the regex min="18" max="120" → number in range type="checkbox" + required → must be checked select + required → must pick a non-empty option ⚠️ title is the message shown when pattern fails. Without title, the browser shows a generic message.
Don't trust required alone for security. Users can disable JavaScript, submit forms via API directly, use curl, or tamper with the page. The required attribute is a UX check — it prevents typos and gives immediate feedback. It is not a validation or security boundary. Always validate the same rules on the server. The two layers are complementary: the browser check improves UX, the server check is what actually protects the data.
⚠️ Common mistakes
The required-attribute mistakes that cost real time.
novalidate on the formDisables native validation. Fix: remove novalidate unless you validate in JS.
nameThe field is required but its value isn't sent. Fix: add name.
<option value="">Choose…</option> with no disabled allows it. Fix: add disabled and selected to the placeholder option.
The error message is generic "match the requested format". Fix: add title with the expected format.
Hidden inputs can be empty but required blocks the form invisibly. Fix: don't add required to hidden inputs, or set a default value.
required on a submit button to workButtons don't take required — it's only for form controls. Fix: it's a no-op, remove it.
Calling form.submit() skips validation. Fix: use form.requestSubmit() instead — it fires the same checks.
CSS can't style the bubble. Fix: use setCustomValidity for custom text, or the constraint validation API for fully custom UI.
❓ Frequently asked
What does the required attribute do?
The required attribute on an input, select, or textarea tells the browser the field must be filled before the form can be submitted. When the user clicks submit with an empty required field, the browser blocks the submission and shows a native validation message. No JavaScript needed. The check is real — the form does not submit until every required field has a value. The message text is browser-provided and cannot be fully styled, only customized via setCustomValidity in JS.
Does required work with checkboxes and radio buttons?
Yes. On a checkbox, required means the box must be checked. On a radio group, required on any one radio in the group makes the whole group required — one option must be selected. The attribute is on one radio, but the browser checks the whole group by name. On a select, required means an option with a non-empty value must be chosen. The first option should have value="" and be disabled so the user has to pick a real one.
Can I style the required error message?
Not directly. The native validation bubble is browser-controlled and cannot be styled with CSS. You can customize the text using setCustomValidity, but the bubble itself — its position, color, font — is up to the browser. If you need a styled error message, use the constraint validation API: check input.validity.valueMissing, set a custom error element, and style that. The required attribute still does the check; you just present the error yourself.
Does required validate email format?
No. required only checks that the field has a value — any value. To validate format, combine it with type="email" (which enforces an @ and a domain), or use the pattern attribute for a custom regex. For email, type="email" required is enough for basic format validation. For stricter rules, use pattern with a specific regex. The required attribute is a presence check, not a format check.
Why is my required field still submitting empty?
Three common causes. (1) The form has novalidate on it — this disables native validation entirely. Fix: remove novalidate. (2) The input is inside a form that uses JavaScript submission with e.preventDefault() — the native check is bypassed. Fix: call form.checkValidity() in your handler before submitting. (3) The input has an empty string as its value from a script (input.value = ''), and the browser considers it filled. Fix: clear with input.value = null or remove the attribute. The required check fires on submit, not on every keystroke.
Should I rely on required alone for validation?
No — the browser check is a UX convenience, not a security measure. Users can disable JavaScript, submit forms via API directly, or bypass the browser entirely with curl. Always validate on the server. The required attribute improves the experience (immediate feedback, no round-trip) but is not a substitute for server-side validation. Use required on the client, and validate the same rules on the server. The two layers are complementary, not alternatives.