In a plain HTML form, one input carries required and another carries pattern="[0-9]{4}". What exactly does the browser do when the user presses the submit button while those constraints are not satisfied?
answer
- nothing reaches the network
- the handler you wrote never runs
- one control gets focus, others do not
- invalid fires per control, no bubbling
- empty value satisfies pattern
basics
~20 sThe browser blocks submission: no submit event fires and no request goes out. It focuses the first invalid control, shows a built-in message bubble beside it, and fires a non-bubbling invalid event on each failing control.
solid answer
~50 sBefore submitting, the browser runs interactive constraint validation over the form's submittable controls. If any control fails, submission is aborted — the form's `submit` event never fires, so a handler that calls `preventDefault()` is never reached and nothing is sent. The browser fires an `invalid` event at each failing control (it does not bubble, and it is cancelable), then reports the first one: it focuses and scrolls to that control and shows the browser's own message bubble, such as "Please fill out this field" for `required` or "Please match the requested format" for `pattern`. Two details worth saying out loud: `pattern` is matched against the whole value, so an empty field does not fail it — you need `required` for that — and all of this is a usability affordance only. Anyone can send the request without a browser, so the server still validates everything.
go deeper
Be able to say that required and pattern stop the submission entirely — no request, no submit event — and that the browser picks the first bad field, focuses it, and shows its own message.
Explain the ordering: validation runs before submit, invalid fires per control and does not bubble, and pattern is anchored to the whole value so an empty field passes it.
Show you have debugged this in production: a hidden or off-screen invalid control makes a form dead-silent, and the native message is unstyleable and in the browser's locale, which is what pushes teams to take the reporting over.
Own the rule that constraint attributes are a funnel for honest mistakes and never a trust boundary; make sure every field the markup constrains is independently enforced server-side and that the two rule sets cannot drift.
## What the attributes actually assert HTML's constraint validation is declarative. Attributes on a control state a condition the value must meet, and the browser enforces them for free: - `required` — the control must have a value; an empty one fails. - `pattern` — the value must match a regular expression. It is matched against the **entire** value, so `^` and `$` are unnecessary; adding them is harmless but reveals a misunderstanding. An empty value never fails `pattern`. - `minlength` / `maxlength` — bounds on the number of characters. `maxlength` mostly acts as a hard cap while typing, so users usually never see an error from it. - `min` / `max` / `step` — bounds and granularity for numeric and date-like controls. The control's `type` also contributes a constraint of its own: `type="email"` and `type="url"` reject values that are not shaped like an address or a URL. ```html <form action="/pay" method="post"> <label for="pin">PIN</label> <input id="pin" name="pin" required pattern="[0-9]{4}" title="Four digits" inputmode="numeric"> <button>Pay</button> </form> ``` ## What happens at submit time When the user activates a submit button, the browser first runs **interactive validation** over the form's submittable controls. If every one of them is satisfied, submission proceeds normally: the `submit` event fires, and unless a script cancels it the request goes out. If any control fails, the sequence is different and this is the part interviewers listen for: 1. Submission is aborted. **The `submit` event does not fire at all.** A script that hangs its logic off `submit` never runs, which is why a form can appear to "do nothing" when a hidden or off-screen control is invalid. 2. An `invalid` event fires at each failing control. It does **not** bubble, so you cannot delegate it on the `<form>` — you attach listeners per control, or use the capture phase. It is cancelable; canceling it suppresses the browser's default report for that control. 3. The browser reports the problem for the first invalid control: it focuses and scrolls to it and displays a native message bubble anchored to it. The text in that bubble comes from the browser, in the **browser's** UI language, and it is not part of the DOM — you cannot style it, select it, or point `aria-describedby` at it. For `pattern` failures browsers surface the control's `title` as additional hint text, which is the only lever the markup gives you over the wording. ## Which controls take part Not every element is validated. A control is skipped when it is `disabled`, `readonly`, `type="hidden"`, a button-ish type, or sits inside a `<datalist>`. The read-only DOM property `willValidate` tells you whether a given element participates at all — a useful thing to check when a constraint appears to be ignored. You can also opt out deliberately. `novalidate` on the `<form>` turns off this automatic validate-and-report step entirely, and `formnovalidate` on a specific submit button turns it off for submissions triggered by that button — the standard way to build a "Save draft" button next to a "Publish" button that does enforce the rules. ```html <button>Publish</button> <button formnovalidate name="action" value="draft">Save draft</button> ``` Importantly, neither attribute disables the constraints themselves. The control still computes its validity, still matches `:invalid`, and `checkValidity()` still reports the failure. Only the browser's automatic UI is suppressed. ## Why it is UX and never a control Everything above happens inside one browser tab. A request built with a command-line client, a mobile app, or a modified page carries none of it. Constraint validation exists to give a user immediate, local feedback instead of a round trip — it narrows the funnel of accidental mistakes. It says nothing about what the server may trust, and the server must re-check every field on its own terms. ## The common misreads Candidates often assume the `submit` event fires and that they can inspect the failure inside it; it does not fire when validation fails. They often assume `pattern` implies `required`; it does not. And they often assume `maxlength` produces an error message; usually it simply stops the keystrokes.
- Does pattern reject an empty field?No. A control with an empty value is never patternMismatch — the constraint only applies once there is something to match. If the field is mandatory you must add `required` alongside `pattern`. Note also that the expression is matched against the whole value, so anchoring it with `^…$` adds nothing.
- How would you add a "Save draft" button that skips validation while "Publish" still enforces it?Put `formnovalidate` on the draft button. It suppresses the browser's validate-and-report step for submissions triggered by that button only, so the draft posts even with empty required fields, while the publish button still blocks. `novalidate` on the `<form>` would disable it for every button, which is not what you want here.
- A required input is failing validation but the user sees no message and the form silently does nothing. What would you check?Usually the invalid control is not visible — collapsed in a hidden panel, scrolled off, or `display:none`. The browser aborts submission and tries to report on a control it cannot show. Check `form.checkValidity()` and iterate the controls to find which one is invalid, and reveal it before the browser has to report on it.
saying these in an interview costs you the question
- Client validation makes server-side checks unnecessary
- The submit event fires and you inspect validity inside it
- pattern needs ^ and $ or it matches substrings
- invalid bubbles, so delegate it on the form
- pattern alone makes a field mandatory