Comprehensive HTML5 Form Validation Example

by Ryan Morris

HTML

<script src="http://modernizr.com/downloads/modernizr.js"></script>
<form>
  <div>
    <label for="title">Title:</label>
    <select id="gender" autofocus>
      <option selected></option>
      <option>Mr.</option>
      <option>Mrs.</option>
      <option>Ms.</option>
      <option>Dr.</option>
    </select>
  </div>
  <div>
    <label for="fullName">Name:</label>
    <input type="text" id="fullName" title="Please provide your full name." x-moz-errormessage="Please provide your full name." required pattern="[a-zA-Z]*" />
  </div>
  <div>
    <label>Gender:</label>
    <label for="genderM">Male:</label>
    <input type="radio" name="gender" id="genderM" title="Please provide your gender." required />
    <label for="genderF">Female:</label>
    <input type="radio" name="gender" id="genderF" required />
  </div>
  <div>
    <label for="age">Age:</label>
    <input type="number" id="age" step="1" min="16" max="120" title="Please provide your age." required />
  </div>
  <div>
    <label for="appointment">Appointment Date:</label>
    <input type="date" id="appointment" title="Please let us know the date on which you have an appointment." required />
  </div>
  <div>
    <label for="telephone">Phone Number:</label>
    <input type="tel" id="telephone" />
  </div>
  <div>
    <label for="email">Email:</label>
    <input type="email" id="email" title="Please provide us with a valid email address so we can contact you and verify your signup." required />
  </div>
  <div>
    <label for="satisfaction">Satisfaction with the Product (1 worst - 10 best):</label>
    <input type="range" id="satisfaction" min="1" max="10" step="1" value="5" />
    <output id="satisfactionOutput">5</output>
  </div>
  <div>
    <label for="comments">Comments:</label>
    <textarea id="comments"></textarea>
  </div>
  <div>
    <label for="agree">Agree to Some Terms:</label>
    <input type="checkbox" id="agree" title="You must accept our terms of service in order to signup for our service."...

CSS

form {
  width: 500px;
  overflow: hidden;
}

div {
  padding: 10px 0;
}

label {
  display: inline-block;
  width: 200px;
  font-weight: bold;
  margin: 0 10px 0 0;
  text-align: right;
}

input[type='text'],
input[type='tel'],
input[type='email'],
input[type='number'] {
  padding: 3px;
}

label[for=genderM],
label[for=genderF] {
  font-weight: normal;
  width: auto;
}

input[type=radio] {
  margin-right: 20px;
}

input[type=submit] {
  float: right;
}

textarea {
  vertical-align: middle;
}

.submitted:invalid {
  border: 1px solid red;
}

.submitted input[type=checkbox]:invalid,
.submitted input[type=radio]:invalid {
  border: none;
  outline: 1px solid red;
}

.required label:after {
  content: '*';
  color: red;
}

.required label[for=genderM]::after,
.required label[for=genderF]::after {
  content: '';
}

output {
  display: none;
}

input[type=range] + output {
  padding-left: 10px;
}

::-webkit-validation-bubble {}

::-webkit-validation-bubble-message {}

::-webkit-validation-bubble-arrow {}

::-webkit-validation-bubble-arrow-clipper {}


/*
<div -webkit-validation-bubble>
  <div -webkit-validation-bubble-arrow></div>
  <div -webkit-validation-bubble-arrow-clipper></div>
  <div -webkit-validation-bubble-message>Error Message</div>
</div>
*/

/*input:required:invalid,*/
input:focus:invalid {
  background-image:...

JavaScript

(function() {
  //IE <= 8
  if ((!window.addEventListener) || (!document.querySelectorAll)) return;

  var requiredFields = document.querySelectorAll('[required]');
  var parent;
  for (var i = 0; i < requiredFields.length; i++) {
    parent = requiredFields[i].parentNode;
    //http://caniuse.com/classlist
    if (parent.classList) {
      parent.classList.add('required');
    }
  }

  var input = document.createElement('input');
  input.setAttribute('type', 'range');
  var rangeTypeSupport = (input.type != 'text');

  if (rangeTypeSupport) {
    var satisfaction = document.getElementById('satisfaction');
    var satisfactionOutput = document.getElementById('satisfactionOutput');
    satisfactionOutput.style.display = 'inline';
    satisfaction.addEventListener('change', function(event) {
      satisfactionOutput.value = event.target.value;
    });
  }

  var submitButton = document.getElementById('submitButton');
  submitButton.addEventListener('click', function() {
    var form = document.getElementsByTagName('form')[0];
    //http://caniuse.com/classlist
    if (form.classList) {
      form.classList.add('submitted');
    }
  });
}());