This screencast is a part of our AtoZ CSS Series. You can find other entries to the series here.
Transcript
:required
is a state based pseudo class that can be useful when styling forms.
Combined with :valid
and :invalid
we can have a lot of control over providing visual feedback to users without having to write lots of JavaScript.
In this episode we’ll learn:
- How to use HTML5 form validation
- Using
:required
and other state-based pseudo classes - A creative technique for displaying validation messages to users
HTML5 Validation
When asking a user to fill out a form, it’s very common to have certain mandatory fields. These might be for their name, email address or credit card details.
In HTML5 we can leverage client-side validation without JavaScript when the behaviour is built into modern browsers.
To create a required field in a form, the required
attribute is added to the HTML.
<form action="#" method="#">
<div>
<input id="name" type="text" required>
<label for="name">Your name</label>
</div>
<div>
<input id="email" type="email" required>
<label for="email">Your email</label>
</div>
<div>
<input id="phone" type="tel" pattern="[0-9]+">
<label for="phone">Your phone number</label>
</div>
<div>
<textarea id="message" required></textarea>
<label for="message">
</div>
<div><input type="submit"></div>
</form>
As required
is a boolean attribute, its presence on an element is enough to set the value so the attribute value doesn’t need to be specified.
It’s also worth noting that in HTML5 elements like input
, that don’t have a closing tag, no longer need to be self-closed with a slash; I think it looks tidier without so have left them off.
With these attributes added to the markup, when I attempt to submit the form without completing those fields, I get a series of tooltip messages asking for the field to be “filled out” – these are auto generated by the browser and can’t be given custom styling as far as I know.
Using :required
With the required
attribute added to the markup, we can use it to add a bit of visual feedback to let users know which fields must be filled in.
The HTML structure is important here, each input and label combination is contained within a <div>
and the label comes after the input. This will become clear later on. We can still have the label appear before the input by floating them to opposite sides of the form container and clearing each container accordingly.
I want to add an asterisk after each label for a required
input. Using knowledge of the general sibling selector and pseudo elements from previous episodes, I can generate the asterisk for any labels that follow a required
input.
If your design requires a different markup structure, with the label before the input, a similar effect could be achieved but you’d need to add a class to the parent container of any required
fields to add the desired styling.
The opposite of required
is optional
and we can make this clear in our form by adding the text “optional” to any inputs that aren’t explicitly required. The :optional
pseudo class has us covered here.
input:optional ~ label:after {
content: "(optional)";
display: block;
color: #888;
}
As our users fill in the form, we can provide extra visual feedback as to whether they have correctly filled in their details by styling the :valid
and :invalid
states.
input:not([type="submit"]):valid:focus,
textarea:valid:focus {
box-shadow: 0 0 10px rgba(101,169,10,0.8);
outline: 0;
}
input:not([type="submit"]):invalid:focus,
textarea:invalid:focus {
box-shadow: 0 0 10px rgba(204,63,133,0.8);
outline: none;
}
These two snippets will add a subtle red shadow behind invalid inputs as they’re being filled in, and a subtle green shadow behind any valid inputs.
Validation messages
We can use the same techniques we’ve already covered, using state based pseudo classes and generating content with pseudo elements to add more descriptive validation messages to our form.
I’ve created a series of messages that will be injected via the content
property of various combinations of valid and invalid fields.
input[type="text"]:focus:invalid~label:before {
content: "Please enter your full name";
}
input[type="email"]:focus:invalid~label:before {
content: "Please enter a valid email";
}
input[type="tel"]:focus:invalid~label:before {
content: "Please only use numbers";
}
textarea:focus:invalid~label:before {
content: "Please enter a message";
}
input:focus:valid~label:before,
textarea:focus:valid~label:before {
content: "Perfect, thanks!";
}
These can then be animated into position when the user focuses the input and will change based on the valid or invalid state.
label:before {
content: "";
position: absolute;
bottom: 0;
right: 0;
font-size: 1rem;
opacity: 0;
transition: 0.2s;
}
input:focus~label:before,
textarea:focus~label:before {
bottom: 100%;
opacity: 1;
}
input:focus:invalid~label:before,
textarea:focus:invalid~label:before {
color: #cc3f85;
}
input:focus:valid~label:before,
textarea:focus:valid~label:before {
color: #65a90a;
}
Now when we fill out the form, we get a bit more info about each step of the process which should be a nice UX boost to a fairly dull form.
Front-end dev and teacher at The General Assembly London. A to Z CSS Screencaster, Founder of sapling.digital and Co-founder of The Food Rush.