Styling HTML Form Validation with CSS
HTML form validation is a powerful feature that helps users fill out forms correctly. When a user submits a form, the browser will automatically validate the form fields and display error messages if the form is invalid. These error messages are displayed by the browser and are not customizable by default. In this blog post, we will explore how to create custom form validation styles using only CSS.
HTML Validation
HTML form validation is a feature that is built into all modern browsers. When a user submits a form, the browser can automatically validate the form fields based on the input type and provided attributes. For example, if a user enters an invalid email address in an email input field, the browser will display an error message indicating that the email address is invalid.
<form>
<label for="email">email</label>
<input type="email" id="email" name="email" required />
<button type="submit">Submit</button>
</form>
In this example, we have a simple form with an email input field that is required. When the user submits the form without entering a valid email address, the browser will display an error message indicating that the email address is required.

Native Validation States in CSS
HTML form elements have built-in validation states that can be styled using CSS. The :valid
and :invalid
states can be used to style form elements based on their validation status. For example, you can change the border color of an input field when it is invalid by using the following CSS:
input:invalid {
border-color: red;
}
However the :invalid
selector is active even when the user has not interacted with the form control. This can be confusing for users as they may see error messages before they have even attempted to fill out the form. To avoid this, you can use the newer CSS pseudo-classes :user-invalid
and :user-valid
which only apply when the user has interacted with the form control.
input:user-invalid {
border-color: red;
}

Custom Validation Messages
The native forms API can provide baseline validation messages form form fields. Example for an email input field with a incorrect email format we see the following:

We can customize the validation message using setting novalidate
on the form element and some custom CSS. For example, we can display a custom inline error message when the user has not entered a valid email address:
<fieldset>
<label for="email">email</label>
<input type="email" id="email" name="email" required />
<span aria-live="polite">valid email required</span>
</fieldset>
Using the CSS :user-invalid
pseudo-class, we can combine it with the CSS :has
selector to display custom inline error messages when a form field is invalid.
[aria-live='polite'] {
color: red;
font-size: 12px;
display: none;
}
fieldset:has(:user-invalid) {
input {
border: 2px solid red;
}
[aria-live='polite'] {
display: block;
}
}

In this example, we leverage the :has
selector to target the fieldset element when it has a invalid form field. We then use the aria-live
attribute to show a custom error message when the user has not entered a valid email address.
Conclusion
By using the :user-invalid
pseudo-class and the :has
selector, you can create custom error messages for form feilds. HTML form validation combined with these newer CSS features can help improve the UX of forms without requiring heavy JavaScript based solutions. Check out the full working demo below!