CSS pseudo-classPseudo-classes

:invalid

Matches form fields whose value breaks an HTML validation rule, such as an empty required field or a malformed email address.

On this page

Example

#
CSS
.error {
  display: none;
  color: #fda4af;
}

.field input:user-invalid {
  border-color: #f43f5e;
}

.field input:user-invalid + .error {
  display: block;
}
Preview

Type text with no @ sign and click outside the field. The message only appears after that interaction, not right away on page load.

Definition and usage

#

The :invalid pseudo-class connects CSS to built-in form validation. A field matches it when its value breaks one of the rules written in the HTML: required on an empty field, type="email" on text that isn’t an address, as well as pattern, min, or max. Its opposite is :valid.

The state updates live, with every keystroke. <form> and <fieldset> also match :invalid if they contain even one invalid field, which lets you, for example, dim the submit button.

The biggest trap: an empty field with required is invalid right from page load. Red borders before the user has typed anything feel like a scolding. The fix is :user-invalid, which only switches on after an interaction: after changing the value and leaving the field, or after trying to submit the form. It works in every major browser as of 2023. The older approach is :not(:placeholder-shown):invalid.

Syntax

#
Syntax
selector:invalid { property: value; }

Common uses

#
  • input:invalid

    Every invalid field at once. The empty required field glows red, even though no one has touched it yet.
  • input:valid

    The opposite: fields with a valid value. Fix the second field into a full address to see the change.
  • input:user-invalid

    The red border only appears after an interaction. Change a field to an invalid value and click elsewhere.
  • input:not(:placeholder-shown):invalid

    The older approach: the error only shows on fields that aren’t empty. An empty required field stays neutral.
  • form:invalid

    The form matches :invalid too, as soon as it has even one invalid field inside it.

Common uses in practice

#

input:invalid

Every invalid field at once. The empty required field glows red, even though no one has touched it yet.
input:invalid { border-color: #f43f5e; }

input:valid

The opposite: fields with a valid value. Fix the second field into a full address to see the change.
input:valid { border-color: #10b981; }

input:user-invalid

The red border only appears after an interaction. Change a field to an invalid value and click elsewhere.
input:user-invalid { border-color: #f43f5e; }

input:not(:placeholder-shown):invalid

The older approach: the error only shows on fields that aren’t empty. An empty required field stays neutral.
input:not(:placeholder-shown):invalid { border-color: #f43f5e; }

form:invalid

The form matches :invalid too, as soon as it has even one invalid field inside it.
form:invalid {
  outline: 2px dashed #f43f5e;
  outline-offset: 4px;
}

Browser support

#

Widely available

Works in all modern browsers, phones included. You can use it without worry.

  • Chrome
  • Edge
  • Firefox
  • Safari

Good practices

#
  • Don’t show errors before the user starts doing anything. Highlight invalid fields through :user-invalid, and save :invalid for things like dimming the submit button.
  • Color alone isn’t enough, since not everyone can tell colors apart. Add a text message or an icon next to the field too.
  • HTML and CSS validation is a convenience for the user, not a safeguard. The data still has to be checked on the server.

Related entries

#

Spotted a mistake or missing an example? Write to us.