Comprehensive HTML5 Form Validation Example

by Ford Heacock

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 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>
 ...

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;
}
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>
*/

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');
        }
    });
}());