While this tutorial has content that we believe is of great benefit to our community, we have not yet tested or
edited it to ensure you have an error-free learning experience. It’s on our list, and we’re working on it!
You can help us out by using the “report an issue” button at the bottom of the tutorial.
Introduction
When it comes to validating the content of input fields on the frontend, things are much easier now than they they used to be. We can use the :required, :optional, :valid and :invalid pseudo-classes coupled with HTML5 form validation attributes like required or pattern to create very visually engaging results. These pseudo-classes work for input, textarea and select elements.
Input pseudo-classes
Here’s an example of the pseudo-classes at work. Let’s start with this HTML markup:
<form action="#">
<input type="text" placeholder="First Name" required>
<input type="email" placeholder="Email" required>
<input type="text" placeholder="Nickname">
<input type="text" placeholder="Favorite pizza topping">
</form>
And let’s apply the following styles:
input {
border: 2px solid;
border-radius: 4px;
font-size: 1rem;
margin: 0.25rem;
min-width: 125px;
padding: 0.5rem;
transition: background-color 0.5s ease-out;
}
input:optional {
border-color: gray;
}
input:required {
border-color: black;
}
input:invalid {
border-color: red;
}
Here’s the result:
See the Pen vYGeLYw by alligatorio (@alligatorio) on CodePen.
In the demo above, <input type="email"
is an HTML5 input type that tells browsers to expect an email address. Because we are also using the required
attribute, modern browsers will only set the input to :valid
when a valid email is entered.
Adding the :focus pseudo-class
Let’s make things even more interesting by also styling according to the focus state and add a background image and color depending on the validity state and only when the input is in focus. We’ll use the same HTML markup.
Here’s our updated CSS:
input {
border: 2px solid;
border-radius: 4px;
font-size: 1rem;
margin: 0.25rem;
min-width: 125px;
padding: 0.5rem;
transition: border-color 0.5s ease-out;
}
input:optional {
border-color: gray;
}
input:required:valid {
border-color: green;
}
input:invalid {
border-color: red;
}
input:required:focus:valid {
background: url("https://assets.digitalocean.com/labs/icons/hand-thumbs-up.svg") no-repeat 95% 50% lightgreen;
background-size: 25px;
}
input:focus:invalid {
background: url("https://assets.digitalocean.com/labs/icons/exclamation-triangle-fill.svg") no-repeat 95% 50% lightsalmon;
background-size: 25px;
}
There are two key changes in the above CSS:
input:required:valid
applies a success state only torequired
inputs. Because technically,optional
inputs are always valid.input:focus:valid' and 'input:focus:invalid
apply to inputs only when they are focused.
And here’s the result:
See the Pen gOrGPxP by alligatorio (@alligatorio) on CodePen.
You could be tempted to add content instead using ::before or ::after on the input, but unfortunately that’s not possible on input elements. One trick would be to have a sibling span element that has content added depending on the validity of the input. Something like this:
input:focus:invalid + span::before { ... }
.