InternotesSharing Web Development Techniques


Self Validating Forms

HTML5 includes additional features for Forms. These include:

  • Making Forms friendlier
  • Validating Form data.

Form friendliness includes:

  • The placeholder attribute to offer hints or explanations of requested data.
  • Specialised input types, such as dates and numbers, which offer specialised interfaces.

In a sense, data validation is also an improvement in friendliness in that it offers immediate feedback rather than requiring the user to wait until the form has been submitted and, possibly, rejected.


Checking the data is always an important requirement. This ensures that the data is:

  • Complete
  • Valid
  • Safe

Note: The data should always be checked at the server, as it is possible to bypass browser validation. Browser validation is purely a convenience to the user.

Traditionally, browser validation has been provided by JavaScript. Today, it is largely built in to browser in the form of HTML5 features.

JavaScript may still be required to check things that are not currently possible in HTML5 validation. For example:

  • Check whether a new email address already exists in the database
  • Check how the value in one field compares with the value of another field

What follows is a discussion of how HTML5 validation, together with CSS, can be used to make a more friendly form.

The Form

For our purposes, we will use the following sample form:

<form id="contact" action="" method="post">
            <input type="email" name="from"
                placeholder="Email Address" maxlength="60" required>
            <span>Please enter a valid email address</span>
                <input type="text" name="name"
                    placeholder="Full Name" maxlength="60" required
                <span>Please enter your full name</span>
            <input type="text" name="phone"
                maxlength="30" placeholder="Phone (Optional)"></label></p>
        <p><label for="contact-subject">Subject:<br>
                <input type="text" name="subject"
                    maxlength="60" placeholder="Subject" required>
                <span>Please enter a subject</span>
            <textarea name="message" placeholder="Message" required></textarea>
            <span>Please enter a message</span>
    <fieldset id="buttons">
        <p><button type="submit" name="send">send message</button></p>

The id attribute is not of itself important for the form. However it will be used to identify this from for CSS and JavaScript.


The form above uses the following features.

  • type="email"

    This actually achieves two things:

    • The value will be checked whether it matches the pattern for an email address.
    • On a mobile device, it will often show the specialised email keyboard.
  • placeholder="…"

    This is ghostly text which will appear when the value is empty.

  • maxlength="…" / minlength="…"

    Sets limits on the acceptable length of the value

  • required

    Indicates that the value cannot be empty.

  • pattern="…"

    A regular expression against which the value is checked.

Form elements would also include the following standard attributes:

  • name="…"

    The name attribute will be associated with the data when the form is submitted to the server, so it is essential for submitting the data. It is also possible to use this attribute locally in CSS and JavaScript.

  • id="…"

    The id attribute never leaves the browser, so is only used locally. Apart from its use in CSS and JavaScript, it can also be used to associate a label using the for attribute. It is not used in this example.

Constraint Validation

In modern browsers, the form data will be checked against any validation requirements. In the above list, this includes:

  • type="email"
  • maxlength="…" / minlength="…"
  • required
  • pattern="…"

Constraint Validation ignores empty fields, unless they are also required. Validation only applies after the user has edited the field value.

The browser will not prevent the user from entering invalid data. However,

  • The browser will highlight invalid fields. Using CSS, you can change how this occurs.
  • The browser will not submit a form which is not completely valid.


Two pseudo classes, :valid and :invalid are available for styling:

  • All validated elements can be selected using the pseudo class
  • In some browsers, you can also use the pseudo class on fieldset and form elements, but not all of them.

In addition to this you can use attribute selectors. For example:

… [required] {}     /* Required fields */
… [type="email"] {} /* Email fields */
… [name="…"] {}     /* One specific field */


CSS can be used to highlight elements, as well as help the user with validation.

Invalid Elements

By default, invalid elements are highlighted with a red fuzzy outline. The following CSS will remove this highlight.

Browsers vary in whether the highlight is implemented as an outline or a box shadow.

/*  Validation
    ================================================ */

    form#contact input:invalid,
    form#contact textarea:invalid {
        outline: none;
        box-shadow: none;
        outline-width: 0;
        /*  you may wish to add a different style instead … */

Required Fields

Naturally, required fields should be marked as such. The following CSS creates a strong border around them.

/*  Highlight Required Fields
    ================================================ */

    form#contact input[required],
    form#contact textarea[required]  {
        border: medium solid #999;

Validation Message

The default message for validated inputs isn’t very useful. For this reason we include a span element.

  • The span element needs to be associated with the input. The most reliable way is:
    • Put the span immediately after the input.
    • Select the span by using the sibling selector (+).

All of this will take place inside the label element which wraps around the input and the span.

  • To position the span:
    • set the containing label to position: relative; this will contain the absolute positioning inside.
    • set the span to position: absolute, and adjust the position relative to the label element

We only want to display the validation message at the right time, so we hide it otherwise.

Normally, to hide an element you can use display: none which virtually removes the element from the layout. However, this will complicate things later, so it is easier to use visibility: hidden, which will simply hide it without removing it.

  • Set the span to visibility: hidden.

/*  Validation Message Box
    ================================================ */

    form#contact label {
        position: relative;
    form#contact textarea+span,
    form#contact input+span {
        box-sizing: border-box;
        font-size: .8em;
        font-weight: bold;
        position: absolute;
        right: 0;
        top: .375em;
        padding: .25em .75em;
        visibility: hidden;

Showing the Message

Showing the message all the time can be overwhelming. For that reason, we will show the message when the text box is in focus, or when there is an error.

  • To select for an input in focus, use input:focus
  • To select for an invalid input, use input:invalid

In both cases, we select the span using the sibling selector:

  • input:focus+span
  • input:invalid+span

When selected, the message will be displayed by setting the visibility property:

  • visibility: visible

The span will be visible when the element is in focus, or, if there is an error, always.

/*  Validation Message
    ================================================ */

    form#contact textarea:invalid+span,
    form#contact input:invalid+span,
    form#contact textarea:focus+span,
    form#contact input:focus+span {
        visibility: visible;

Displaying Validity

If an element is invalid, we will change the message span to white text on a red background. Otherwise, it will remain with the default styling.

/*  Correctness
    ================================================ */

    form#contact textarea:invalid+span,
    form#contact input:invalid+span {
        background-color: red;
        color: white;
        border: thin solid red;

Displaying the Status

Apart from the stark error message, we will also display a more subtle status by adding a symbol after the message. This will be regardless of whether the actual message span is visible.

The :after pseudo element can be used to append content to an element.

  • Refer to the pseudo element using span:after
  • Since the span itself may not be visible, make sure that the :after pseudo element by setting visibility: visible
  • Add some room with the margin-left property.

The status only applies when the data is valid or invalid. This does not include empty data (unless it is required).

The actual status will be set by setting the content property to something suitable.

  • Select the validated element using :valid+span:after or :invalid+span:after
  • Set the content to something suitable.
/*  Satus
    Possible Symbols: ✓ ⁉︎ ☹︎ ☺︎ ‼︎
    ================================================ */

    form#contact :valid+span:after,
    form#contact :invalid+span:after {
        visibility: visible;
        margin-left: 1em;
    form#contact :valid+span:after {
        content: "✓";
        color: green;
    form#contact :invalid+span:after {
        content: "⁉︎";
        color: white;
        font-weight: bold;

Disabling the Submit Button

In modern browsers, the form will not submit if there are any validation errors. However, it would be better if the actual Submit button makes the point clear.

  • To select the invalid submit button, use the form:invalid pseudo class.
  • Change the appearance of the button with the opacity property.

This changes the appearance of the button, but it is still active. To actually deactivate the button, use the pointer-events property, which will disable clicking:

  • Disable the button by setting pointer-events: none

The bad news is that Neither IE nor Edge support form:invalid. However, they will still not submit the form, so this is only a minor tragedy.

/*  Disable Invalid Form
    Doesn’t work on IE or Edge, of course,
    but form will still not submit.
    ================================================ */

    form#contact:invalid button[type="submit"] {
        opacity: .3;
        pointer-events: none;