Published: November 8, 2023

<br />

> [!TIP]
> **Celebration:** These web features are now available in all three major browser engines, and became **Baseline Newly available** as of October, 2023.

<iframe src="https:///frame/articles/user-valid-and-user-invalid-pseudo-classes/index_c8e852063f26475bd7160e9d52a835559bb2429304244127a460d8e3029503e4.frame" class="framebox inherit-locale " allow="clipboard-write https://" allowfullscreen is-upgraded></iframe>

User input is one of the most sensitive concerns in any user interface. A usable
application must help users see, understand, and fix any mistakes in their
input. The `:user-valid` and `:user-invalid` pseudo-class selectors help improve
the user experience of input validation by giving feedback about mistakes only
after a user has changed input. With these new selectors, there's no longer a
need to write stateful code to keep track of input a user has changed.

## The user interaction pseudo-class selectors

The `:user-valid` and `:user-invalid` pseudo-class selectors are similar to the
existing `:valid` and `:invalid` pseudo-classes. Both match a form control based
on whether its current value satisfies its validation constraints. However, the
advantage of the new `:user-valid` and `:user-invalid` pseudo-classes is that
they match a form control only after a user has significantly interacted with
the input.

A form control that is required and empty will match `:invalid` even if a user
has not started interacting with the page. However, that same form control won't
match `:user-invalid` until the user has changed the input and left it in an
invalid state.

### Use the `:user-valid` and `:user-invalid` pseudo-classes

Use these pseudo-classes to style input, select, and textarea controls, as shown
in the following examples:

    input:user-valid,
    select:user-valid,
    textarea:user-valid {
      border-color: green;
    }

    input:user-invalid,
    select:user-invalid,
    textarea:user-invalid {
      border-color: red;
    }

    <input required="required" />

    <select required="required">
      <option value="">Choose an option</option>
      <option value="1">One</option>
    </select>

    <textarea required="required"></textarea>

![An image that combines 3 screenshots side by side for comparison. Each screenshot shows a web form with the same input, select, and textarea controls. The first screenshot shows the form in its initial state before any user input. The control borders are gray and the help text below explains that each control will currently match the :invalid pseudo-class selector. The second screenshot shows the same form after a user has provided input for each control. The control borders are green and the help text below explains that each control will currently match both the :valid and :user-valid pseudo-class selectors. The third and final screenshot shows the same form after a user has removed all of their input. The control borders are red and the help text below explains that each control will currently match both the :invalid and :user-invalid pseudo-class selectors.](https://web.dev/static/articles/user-valid-and-user-invalid-pseudo-classes/image/form-state-screenshots.png)

The selectors match based on a combination of user interactions and validation
constraints. Interact with the following demo to see them in action:
<iframe allow="camera; clipboard-read; clipboard-write; encrypted-media; geolocation; microphone; midi;" loading="lazy" src="https://codepen.io/web-dot-dev/embed/wvNJGrO?height=600&amp;theme-id=dark&amp;default-tab=result&amp;editable=true" style="height: 100%; width: 100%; border: 0;" title="Pen wvNJGrO by web-dot-dev on Codepen"></iframe>

### Better user experience with less code

Without these pseudo-classes, achieving the user experience enabled by
`:user-valid` and `:user-invalid` required writing extra stateful code. That
code needed to keep track of the initial value, the current focus state of the
input, the extent of the user's changes to the value, run an extra validity
check, and finally add a class to select for styling. You can now rely on the
browser to handle all of this automatically.

## More resources

- [:user-valid - MDN web docs](https://developer.mozilla.org/docs/Web/CSS/:user-valid)
- [:user-invalid - MDN web docs](https://developer.mozilla.org/docs/Web/CSS/:user-invalid)
- [User-interaction Pseudo-classes - W3C Editor's Draft](https://drafts.csswg.org/selectors-4/#user-pseudos)
- [Form Constraint Validation - MDN web docs](https://developer.mozilla.org/docs/Learn/Forms#constraint_validation)
- [Forms Accessibility Tutorial - Web Accessibility Initiative](https://www.w3.org/WAI/tutorials/forms/)