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 { ... }
.