AtoZ CSS Screencast: The Required Pseudo Class

Guy Routledge
Guy Routledge

Loading the player…

This screencast is a part of our AtoZ CSS Series. You can find other entries to the series here.


: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="#"> 
    <input id="name" type="text" required> 
    <label for="name">Your name</label> 
    <input id="email" type="email" required> 
    <label for="email">Your email</label> 
    <input id="phone" type="tel" pattern="[0-9]+"> 
    <label for="phone">Your phone number</label> 
    <textarea id="message" required></textarea> 
    <label for="message"> 
  <div><input type="submit"></div> 

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.

textarea:valid:focus {
  box-shadow: 0 0 10px rgba(101,169,10,0.8);
  outline: 0;
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";
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;
textarea:focus~label:before {
  bottom: 100%;
  opacity: 1;
textarea:focus:invalid~label:before {
  color: #cc3f85;
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.