Form part 2 - Submit your form

Associated themes :

Introduction #

We saw in the first part how to structure your form while respecting accessibility criteria.

In this second part, we will make it easier for the user to enter the fields and set up an error management system when validating our form.

We will continue to base our examples on our Part 1 registration form.

In this example, we are using the Boosted library which is the web version of our Orange Design System (ODS). This allows you to obtain forms whose design complies with the Orange charter.

Submitting a form #

Required Field #

In forms, it is common for fields to be required. These fields should be made clear to users.

To achieve this, several solutions exist:

  • programmatically, you must use the required or aria-required="true" attribute in the input tag of our fields , using these attributes will allow assistive technologies (AT) to indicate that the field is required.
  • users not using assistive technologies must also be informed that the field is mandatory; it is therefore necessary to add a visual identification that is not based solely on the color (for example, by explicitly mentioning "mandatory"). If this identification is not made via explicit text, for example, an asterisk (*), the meaning must be explained, such as, for example, "All mandatory fields are marked with an *", which will be placed beginning of the form.

Example #

In our registration example, several fields can be considered mandatory in order to validate your registration: email, password, first name and last name.

They must therefore be specified to users.

All mandatory fields are marked with an *

Your password must contain at least 6 characters.

Example code :

  
  <div class="col-md-8">
    <form id="formulaire" class="border border-secondary p-3 my-2">
      <p>All mandatory fields are marked with an *</p>
      <div class="mb-2">
        <label for="email" class="form-label">Email * </label>
        <input type="text" class="form-control" id="email" required/>
      </div>
      <label for="password" class="form-label">Password *</label>
      <div class="mb-2 input-group">
        <input type="password" class="form-control" id="password" required aria-describedby="passwordHelpBlock"/>
        <span class="input-group-text">
          <button type="button" class="btn btn-icon btn-secondary btn-sm" id="password_visibility" title="Show password" >
            <svg aria-hidden="true" focusable="false" fill="currentColor" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 1000 1000"></svg>
          </button>
        </span>
      </div>
      <div id="passwordHelpBlock" class="form-text">
          Your password must contain at least 6 characters.
      </div>
      <div class="mb-2">
        <label for="name" class="form-label">Last Name *</label>
        <input type="text" class="form-control" id="name" required/>
      </div>
      <div class="mb-2">
        <label for="firstname" class="form-label">First Name * </label>
        <input type="text" class="form-control" id="firstname" required/>
      </div>
      <button type="submit" class="btn btn-primary">Submit</button>
    </form>
  </div>
  

Error management #

During validation, if mandatory fields are not filled in, or if the format of the data entered is not valid, the user must be informed.

To achieve this, you need 

  • Use the aria-invalid="true" attribute to indicate an input error to AT users
  • Display explicit error messages for all other users
  • If necessary, suggest corrections

If error messages prevent the validation of the form, rather than listing the errors at the beginning of the form in a banner, we can, for each field in error, warn the user (see above).

For each field in error, the messages must be explicit, which means:

  • Be clear and unambiguous ("invalid field" is not enough, specify which field is invalid and, if possible, how it is invalid)
  • Be specific and relevant
  • Provide suggestions for corrections and ways to correct
  • Make sure errors are in plain text, avoid capitals.
  • Don't just use visual cues or just color to point out errors.
  • Leave the send button active in all circumstances. Some websites enable the submit button only if the form is filled out correctly, it's a bad idea.
  • Provide the necessary instructions and be as specific as possible on the errors made in order to facilitate the filling of the fields by the users.
  • Make sure errors are visually identifiable on the web page.

Example #

In our registration example, several fields may be in error:

  • For mandatory fields, it will be necessary to specify which mandatory field is in error
  • For fields requiring a specific data format, such as email, in the error message, we will specify the field in error and provide correction assistance

All required fields are marked with *

Error

The email field is required

Error

Please fill in a valid Email (name@gmail.com)

Error

The Password field is requirede

Error

Please enter a valid password (minimum 6 characters)

Your password must contain at least 6 characters.
Error

The Last Name field is required

Error

The First Name field is required

Gender

In the example above:

  • Mandatory fields that are not completed have relevant and unique error messages (example: The email field is mandatory)
  • Fields with an invalid entry have a specific message that gives suggestions for correction (example: Please enter a valid Email (lastnamefirstname@gmail.com))
  • Error messages are linked to the field using the aria-describedby or aria-labelledby attribute, which will allow assistive technologies to render the 'information
  • The keyboard focus is put on the first field in error in order to be able to rescan the whole form

Using the autocomplete attribute #

The autocomplete attribute makes it easier to fill in fields that contain personal information. All fields whose type is listed in 7. InputPurposes for User Interface Components must contain the autocomplete attribute.

In our example the fields below should have an autocomplete attribute:

  • Email with autocomplete="email"
  • Password with autocomplete="new-password"
  • Name with autocomplete="name"
  • First name with autocomplete="given-name"

Complete example #

The full HTML and Javascript code that allowed us to make this accessible registration form.

  
  <div class="col-md-8">
  <form id="formulaire_2" class="border border-secondary p-3 my-2">
    <p>All required fields are marked with *</p>
    <div class="mb-2">
      <label for="email_2" class="form-label">Email *</label>
      <input type="text" class="form-control" id="email_2" required/>
      <div id="erroremailDiv" class="alert alert-danger alert-sm d-none">
        <span class="alert-icon"><span class="visually-hidden">Error</span></span>
        <p id="erroremail1">The email field is required</p>
      </div>
      <div id="erroremailDiv2" class="alert alert-danger alert-sm d-none">
        <span class="alert-icon"><span class="visually-hidden">Error</span></span>
        <p id="erroremail2">Please fill in a valid Email (name@gmail.com)</p>
      </div>
    </div>
    <label for="password_2" class="form-label">Password *</label>
    <div class="mb-2 input-group">
      <input type="password" class="form-control" id="password_2" aria-describedby="passwordHelpBlock_2" required/>
      <span class="input-group-text">
        <button type="button" class="btn btn-icon btn-secondary btn-sm" id="password_visibility_2" title="Show password" >
          <svg aria-hidden="true" focusable="false" fill="currentColor" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 1000 1000">
            <defs>
              <style>
                .cls-1 {
                  fill-rule: evenodd;
                }
              </style>
            </defs>
            <path class="cls-1" d="M513.081,250.129c-4.017,0-8.041-.129-12.081-0.129s-8.064.129-12.081,0.129C301.335,250.129,111.491,382.343,50,500c61.491,117.656,249.335,249.871,436.919,249.871,4.017,0,8.04.129,12.081,0.129s8.064-.129,12.081-0.129C698.665,749.871,888.51,617.656,950,500,888.51,382.343,700.665,250.129,513.081,250.129ZM498.62,680a180,180,0,1,1,180-180A180,180,0,0,1,498.62,680Zm-378.2-179.963c29.782-41.595,77.4-84.081,132.916-117.816a545.263,545.263,0,0,1,55.918-29.695,239.848,239.848,0,0,0,.78,295.942,537.117,537.117,0,0,1-57.553-30.6C197.469,584.226,150.153,541.734,120.417,500.034Zm626.25,117.747a544.106,544.106,0,0,1-60.236,31.655,239.784,239.784,0,0,0-.761-299.823,536.07,536.07,0,0,1,61.852,32.517c55.01,33.642,102.326,76.136,132.061,117.836C849.8,541.564,802.185,584.045,746.667,617.781ZM597.931,453.153a48.227,48.227,0,1,1-62.472-56.6A109.731,109.731,0,1,0,597.931,453.153Z" />
          </svg>
        </button>
      </span>
    </div>
    <div id="errorpasswordDiv" class="alert alert-danger alert-sm d-none">
        <span class="alert-icon"><span class="visually-hidden">Error</span></span>
        <p id="errorpassword1">The Password field is requirede</p>
      </div>
      <div id="errorpasswordDiv2" class="alert alert-danger alert-sm d-none">
        <span class="alert-icon"><span class="visually-hidden">Error</span></span>
        <p id="errorpassword2">Please enter a valid password (minimum 6 characters)</p>
      </div>
    <div id="passwordHelpBlock_2" class="form-text">
        Your password must contain at least 6 characters.
    </div>
    <div class="mb-2">
      <label for="name_2" class="form-label">Last Name *</label>
      <input type="text" class="form-control" id="name_2" required/>
      <div id="errorname" class="alert alert-danger alert-sm d-none">
        <span class="alert-icon"><span class="visually-hidden">Error</span></span>
        <p id="errorname1">The Last Name field is required</p>
      </div>
    </div>
    <div class="mb-2">
      <label for="firstname_2" class="form-label">Fist Name *</label>
      <input type="text" class="form-control" id="firstname_2" required/>
      <div id="errorfirstname" class="alert alert-danger alert-sm d-none">
        <span class="alert-icon"><span class="visually-hidden">Error</span></span>
        <p id="errorfirstname1">The First Name field is required</p>
      </div>
    </div>
    <fieldset>
      <legend>Gender</legend>
      <div class="form-check form-check-inline">
        <input class="form-check-input" type="radio" name="inlineRadioOptions_2" id="M_2" value="Mr" selected>
        <label class="form-check-label" for="M_2">Mr</label>
      </div>
      <div class="form-check form-check-inline">
        <input class="form-check-input" type="radio" name="inlineRadioOptions_2" id="Mme_2" value="Mrs">
        <label class="form-check-label" for="Mme_2">Mrs</label>
      </div>
      <div class="form-check form-check-inline">
        <input class="form-check-input" type="radio" name="inlineRadioOptions_2" id="Non-binaire_2" value="No-binary" >
        <label class="form-check-label" for="Non-binaire_2">No-binary</label>
      </div>
    </fieldset>
    <div class="mb-2">
      <label for="adresse_2" class="form-label">Address</label>
      <input type="text" class="form-control" id="adresse_2"/>
    </div>
    <div class="mb-2">
      <label for="adresse2_2" class="form-label">Additional address</label>
      <input type="text" class="form-control" id="adresse2_2"/>
    </div>
    <div class="mb-2">
      <label for="ville_2" class="form-label">City</label>
      <input type="text" class="form-control" id="ville_2"/>
    </div>
    <div class="mb-2">
      <label for="cp_2" class="form-label">Zip Code</label>
      <input type="text" class="form-control" id="cp_2"/>
    </div>
     <button id="submit" class="btn btn-primary">Submit</button>
     <div id="alertsucces" class="alert alert-success d-none" role="alert">
      <span class="alert-icon"><span class="visually-hidden">Success</span></span>
      <p>The validation of the form is successful.</p>
    </div>

  </form>
</div>
  
  
  document.addEventListener("DOMContentLoaded", function(event) {
    document.getElementById("password_visibility").onclick = function (e){
        let password = document.getElementById("password");
        if(password.type=="password"){
            password.type="text";
            this.title ="Hide password";
        }
        else{
            password.type="password";
            this.title ="Show password";
        }
    }

    document.getElementById("password_visibility_2").onclick = function (e){
        let password = document.getElementById("password");
        if(password.type=="password"){
            password.type="text";
            this.title ="Hide password";
        }
        else{
            password.type="password";
            this.title ="Show password";
        }
    }

    document.getElementById("submit").onclick = function (e){
        e.preventDefault();

        let error=false;

        let email = document.getElementById("email_2");
        let password = document.getElementById("password_2");
        let name = document.getElementById("name_2");
        let firstname = document.getElementById("firstname_2");

        if(firstname.value==""){
            error=invalid(firstname,"errorfirstname1");
            document.getElementById("errorfirstname").classList.remove("d-none");

        }
        else{
            valid(firstname);
            document.getElementById("errorfirstname").classList.add("d-none")
        }

        if(name.value==""){
            error=invalid(name,"errorname1");
            document.getElementById("errorname").classList.remove("d-none");
        }
        else{
            valid(name);
            document.getElementById("errorname").classList.add("d-none")
        }

        if(password.value==""){
            error=invalid(password,"errorpassword1 passwordHelpBlock_2");
            document.getElementById("errorpasswordDiv").classList.remove("d-none");
        }
        else{
            if(password.value.length>=6){
                valid(password);
                document.getElementById("errorpasswordDiv").classList.add("d-none")
                document.getElementById("errorpasswordDiv2").classList.add("d-none")
                password.setAttribute("aria-describedby", "passwordHelpBlock_2");
            }
            else{
                error=invalid(password,"errorpassword2 passwordHelpBlock_2");
                document.getElementById("errorpasswordDiv").classList.add("d-none")
                document.getElementById("errorpasswordDiv2").classList.remove("d-none");
            }   
        }
        if(email.value==""){
            error=invalid(email,"erroremail1");
            document.getElementById("erroremailDiv").classList.remove("d-none");
        }
        else{
            if(validateEmail(email.value)){
                valid(email);
                document.getElementById("erroremailDiv").classList.add("d-none")
                document.getElementById("erroremailDiv2").classList.add("d-none")
            }
            else{
                error=invalid(email,"erroremail2");
                document.getElementById("erroremailDiv").classList.add("d-none")
                document.getElementById("erroremailDiv2").classList.remove("d-none");
            }
            
        }

        if(error){
            document.getElementById("alertsucces").classList.add("d-none")
        }
        else{
            document.getElementById("alertsucces").classList.remove("d-none")
        }
    }

    function valid (element){
        element.setAttribute("aria-invalid", false)
        element.classList.remove("is-invalid");
        element.removeAttribute("aria-describedby")
    }

    function invalid(element,errorDiv){
        element.setAttribute("aria-invalid", true);
        element.classList.add("is-invalid");
        element.setAttribute("aria-describedby", errorDiv);
        element.focus();
        return true;
    }

    const validateEmail = (email) => {
        return String(email)
          .toLowerCase()
          .match(
            /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
          );
      };
})
  

Form part 1 - Structure your form