HTML5 form validation + bootstrap

by trixta

HTML

<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css">
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap-theme.min.css">
<form action="#" class="form-horizontal validate">
    <div class="form-group">
        <label for="inputEmail3" class="control-label">Email*</label>
        <input type="email" class="form-control" id="inputEmail3" placeholder="Email" required />
    </div>
    <div class="form-group">
        <label for="inputPassword3" class="control-label">Password*</label>
        <input type="password" class="form-control" id="inputPassword3" placeholder="Password" required />
    </div>
    <div class="form-group">
        <button type="submit" class="btn btn-primary">submit</button>
    </div>
</form>

CSS

body {
    margin: 10px;
    padding: 10px;
}
form {
    max-width: 480px;
    margin: auto;
}
.form-group >[class*="col-"] + .ws-errorbox {
    padding: 0 15px;
}

JavaScript

(function () {
    //if no validation or classlist feature we don't enhance
    if (!('noValidate' in document.createElement('form')) || !document.createElement('a').classList) {
        return;
    }

    var elemProto = Element.prototype;
    if (!elemProto.matches) {
        elemProto.matches = elemProto.matchesSelector || elemProto.mozMatchesSelector || elemProto.webkitMatchesSelector || elemProto.msMatchesSelector;
    }

    Array.prototype.forEach.call(document.querySelectorAll('form.validate'), function (form) {
        form.noValidate = true;

        form.addEventListener('submit', function (e) {
            if (!form.checkValidity()) {
                e.preventDefault();
                form.querySelector('input:invalid, select:invalid, textarea:invalid').focus();
            }
        });

        form.addEventListener('blur', function (e) {
            if (e.target.matches(':invalid')) {
                setInvalid(e.target);
            } else {
                removeInvalid(e.target);
            }
        }, true);

        form.addEventListener('invalid', function (e) {
            setInvalid(e.target);
        }, true);
    });


    function setInvalid(element) {
        var message;
        var parent = element.parentNode;

        if (!parent.classList.contains('has-error')) {
            message = document.createElement('div');
            message.className = 'help-block';
            message.innerHTML = element.validationMessage;
            parent.classList.add('has-error');
            parent.appendChild(message);
        } else {
            parent.querySelector('.help-block').innerHTML = element.validationMessage;
        }
    }

    function removeInvalid(element) {
        var parent = element.parentNode;
        if (parent.classList.contains('has-error')) {
            parent.classList.remove('has-error');
            parent.removeChild(parent.querySelector('.help-block'));
        }
    }

})();