Encodera

Thanks for reading!

Donate to the site — we work hard for you.

How to highlight errors in a form

Short answer

The :user-invalid pseudo-class fires when the user entered a wrong value and left the field:

<style>
  input { padding: 8px; border: 2px solid silver; border-radius: 6px; }
  input:user-invalid { border-color: crimson; }
  input:user-valid { border-color: seagreen; }
</style>
 
<input type="email" placeholder="Email" required>

Type anna, then click outside the field — the border turns red. Fix it to anna@example.com — it turns green.

An error message

The hint is kept hidden and shown when the field next to it becomes invalid. The :has() pseudo-class checks the field inside the label:

<style>
  .error { display: none; color: crimson; font-size: 14px; }
  label:has(:user-invalid) .error { display: block; }
</style>
 
<label>
  Email <input type="email" required>
  <span class="error">Enter an email like anna@example.com</span>
</label>

What "invalid" means

A field is invalid if it breaks its constraints: required, type, pattern, minlength, min, max. So first describe the rules with attributes, and CSS only shows the result of the check.

Common mistake

The older :invalid pseudo-class is used. It fires right on load, so an empty required form greets the user with red borders before they have typed anything:

<style>
  input:invalid { border: 2px solid crimson; }
</style>
 
<input type="email" placeholder="Already red" required>

Functions used in this recipe

  • :user-invalid — Matches an invalid field only after the user has interacted with it; `:user-valid` is the opposite.
  • :valid — `:valid` matches a field whose value passes the built-in checks; `:invalid` matches one that does not.
  • :has() — Matches an element that contains something matching the selector in brackets — the "parent selector".
  • required — Makes a field required: the form will not submit while it is empty.
  • <input> — An input field; its kind is set by the `type` attribute.

Thanks for reading!

Donate to the site — we work hard for you.