Create custom form validation with CSS only

Validate forms with just CSS? Yes, it’s possible!

Form validation is often handled with JavaScript, but did you know CSS can do a lot of the heavy lifting?

It works thanks to 4 built-in pseudo classes:

  • :valid → The input meets all constraints.
  • :invalid → The input fails validation.
  • :user-valid → The input is valid and the user has interacted with it.
  • :user-invalid → The input is invalid but only after the user typed something and left the field.

You can also define validation rules directly in HTML using attributes like required, type, and pattern.

CSS selectors combined with these pseudo-classes allow you to style form elements based on their validation state. You can show or hide messages, change input borders, or visually guide users as they type.

Regarding browser support:

  • :valid & :invalid have more than 96%
  • :user-valid & :user-invalid have a bit more than 90%

This approach isn’t a full replacement for JavaScript validation, but it’s a powerful way to enhance forms with minimal effort.

Codepen link: https://codepen.io/theosoti/pen/ogNZzdJ

<div class="field">
  <label for="email">Input Email</label>
  <input
    id="email"
    required="required"
    aria-describedby="input-message"
    type="email"
    pattern="[^@\s]+@[^@\s]+\.[^@\s]+"
  />
  <ul class="validation" role="list">
    <li data-matches="valid">🔵 Input <code>:valid</code></li>
    <li data-matches="invalid">🟠 Input <code>:invalid</code></li>
    <li data-matches="user-valid">🟢 Input <code>:user-valid</code></li>
    <li data-matches="user-invalid">🔴 Input <code>:user-invalid</code></li>
  </ul>
</div>
input:user-valid {
  --state-color: green;
}

input:user-invalid {
  --state-color: red;
}

input:valid + .validation [data-matches="valid"],
input:invalid + .validation [data-matches="invalid"] {
  display: block;
}

input:user-valid + .validation [data-matches="user-valid"],
input:user-invalid + .validation [data-matches="user-invalid"] {
  display: block;
}

input {
  --state-color: black;

CSS validation patterns are excellent for immediate feedback, but they should complement real form validation logic. Keep messages clear and state changes gentle so users understand how to recover quickly.

For production forms, test keyboard order, disabled states, and validation messages with realistic labels. Native behavior should remain intact while visual polish improves.

You Don’t Need JavaScript ebook mockup

I wrote a guide about building modern UI with HTML and CSS first. It covers practical patterns you can use before reaching for JavaScript.

Learn more

    No strings attached, unsubscribe anytime!

    Other short articles you might like

    Explore more articles on front-end development, covering HTML, CSS and JavaScript for building high-performance websites.