Avatar of Geoff Graham
Geoff Graham on (Updated on )

DigitalOcean provides cloud products for every stage of your journey. Get started with $200 in free credit!

The :user-invalid is a CSS pseudo-class that is under proposal in the CSS Selectors Level 4 working draft that selects a form element based on whether the value—as entered by a user—is valid when checked against the what is specified as an accepted value in the HTML markup after the end user has interacted with the form beyond that input. In fact, :user-invalid has been called “The User Interaction Pseudo-class” because it is unique in identifying a user action in selecting an element.

Take the following HTML markup for a basic form with a numeric field:

  <label for="quantity"> Quantity:</label>
  <input id="quantity" max="10" min="0" type="number" value="11" />
  <!-- Rest of the form... -->

The numeric range set by the HTML markup for the input is between 1 and 10 but the default value has been set to 11. That means the value is invalid as soon as the form loads.

However, the :user-invalid pseudo-class will not take effect until after the user has actually interacted with the form beyond entering it in the field. That interaction is the difference between :user-invalid and :invalid. The same principle applies for entered form values that are set by :in-range, :out-of-range and :required.

input:user-invalid {
  color: red;

The following image illustrates the different states between :valid, and :user-invalid based on the HTML example above.

The difference between a valid value (left) and an invalid value entered by a user after interacting with the form.

The confusing thing with here is how closely related :invalid and :user-invalid are. If used together, it may be tough to distinguish the two:

input:invalid {
  color: red;

input:user-invalid {
  color: red;
The difference between :invalid (center) and an invalid value entered by a user (right) can be tough to distinguish

Using one over the other or having distinct styling between the two might prove to be a better user experience in a real-life use case.

Browsers can decide how and when elements are matched

It’s worth calling out that when :user-invalid matches form fields that are :invalid, :out-of-range, or blank but :required, it’s doing so “between the time the user has attempted to submit the form and before the user has interacted again with the form element.” However, the spec leaves room for browsers to make their own decisions for when elements match:

User-agents may allow them to match such elements at other times, as would be appropriate for highlighting an error to the user. For example, a UA may choose to have :user-invalid match an :invalid element once the user has typed some text into it and changed the focus to another element, and to stop matching only after the user has successfully corrected the input.

Once the value that the user has entered is determined to be an invalid entry, we can select the element.

Browser support

It’s only Firefox at the time of writing, which was implemented :user-invalid in Firefox 88. The Chromium project has an open bug ticket (star it!) to implement it in Blink-based browsers (i.e. Chrome and Edge). There’s an open WebKit ticket to add support in Safari as well.

Check caniuse for the latest browser support.

More information