
A small form validation script that automatically highlights invalid form fields and displays custom error messages using HTML5 validation attributes.
How to use it:
Add required and error message to the form fields using the following data attributes:
<form class="form" action="#_">
<fieldset>
<legend>My informations:</legend>
<p class="requirement"><em>Fields followed by (*) are required</em></p>
<div class="form-field">
<label id="optional-label" for="optional">Optional field:</label>
<input id="optional" name="optional" type="text" placeholder="optional">
</div>
<div class="form-field">
<label id="lastname-label" for="lastname">Lastname: <span aria-hidden="true">(*)</span></label>
<input id="lastname" name="lastname" type="text" placeholder="Dupond" required
pattern="[a-zA-Zçàéèëìîïòõôûùñ '-]+"
title="Lettres uniquement"
aria-labelledby="lastname-label"
data-msg-required="The Lastname field is required."
data-msg-error="The Lastname field should contain only letters.">
</div>
<div class="form-field">
<label id="firstname-label" for="firstname">Firstname: <span aria-hidden="true">(*)</span></label>
<input id="firstname" name="firstname" type="text" placeholder="Jean" required
pattern="[a-zA-Zçàéèëìîïòõôûùñ' -]+"
title="Lettres uniquement"
aria-labelledby="firstname-label"
data-msg-required="The Firstname field is required."
data-msg-error="The Firstname field should contain only letters.">
</div>
<div class="form-field">
<label id="email-label" for="email">Email: <span aria-hidden="true">(*)</span></label>
<input id="email" type="email" placeholder="[email protected]" required
aria-labelledby="email-label"
data-msg-required="The Email field is required."
data-msg-error="The Email field is invalid">
</div>
<div class="form-field">
<label id="phone-label" for="phone">Phone number: (0611223344 or +33611223344) <span aria-hidden="true">(*)</span></label>
<input id="phone" name="phone" type="tel" placeholder="0611223344" required
pattern="^((\+\d{1,3}(-| )?\(?\d\)?(-| )?\d{1,5})|(\(?\d{2,6}\)?))(-| )?(\d{3,4})(-| )?(\d{4})(( x| ext)\d{1,5}){0,1}$"
aria-labelledby="phone-label"
data-msg-required="The Phone field is required."
data-msg-error="The Phone field is invalid. It must contain only numbers and/or the sign '+'">
</div>
<div class="form-field">
<label id="civility-label" for="civility">Civility: <span aria-hidden="true">(*)</span></label>
<select id="civility" name="civility" required
aria-labelledby="civility-label"
data-msg-required="The Civility field is required.">
<option value="" disabled selected>Select an option</option>
<option value="1">Mrs.</option>
<option value="2">Mr.</option>
</select>
</div>
<div class="form-field">
<label id="password-label" for="password">Password: (<abbr tabindex="0" title="required">*</abbr>)
<span class="input-help">Password must be 8+ characters and include letters (at least one Uppercase) AND number(s)</span></label>
<input id="password" name="password" type="password" required
pattern="(?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$"
aria-labelledby="password-label"
data-msg-required="The Password field is required."
data-msg-error="Password field is invalid. It must be 8+ characters and include letters (at least one Uppercase) AND number(s)">
</div>
<div class="form-field">
<label id="radio-label" for="radio">
<input type="radio" id="radio" name="radio" required
aria-labelledby="radio-label"
data-msg-required="The Password field is required.">
Radio
</div>
<div class="form-submit">
<input type="reset">
<input type="submit">
</div>
</fieldset>
</form>The main JavaScript to activate the custom HTML5 form validator.
"use strict";
const inputs = document.querySelectorAll('input[required],select[required],textarea[required]'),
oForm = document.querySelector('.form'),
defaultRequiredMsg = "This field is required.",
defaultErrorMsg = "This field is invalid.";
function formCheck(input){
const inputParent = input.closest('.form-field'),
inputId = input.id;
let errorMsg = input.getAttribute('data-msg-error'),
requireMsg = input.getAttribute('data-msg-required');
let label_error;
input.setAttribute("aria-invalid", !input.checkValidity());
if(!input.checkValidity()) {
if(!document.querySelector('#'+inputId+"-error")){
label_error = document.createElement('p');
label_error.setAttribute("id", inputId+"-error");
label_error.setAttribute('class','msg-form-error');
inputParent.insertBefore(label_error, input.nextSibling);
} else {
label_error = document.querySelector('#'+inputId+"-error");
}
if (input.value === ''){
requireMsg ? requireMsg = requireMsg : requireMsg = defaultRequiredMsg;
label_error.innerHTML = requireMsg;
}else{
errorMsg ? errorMsg = errorMsg : errorMsg = defaultErrorMsg;
label_error.innerHTML = errorMsg;
}
inputParent.classList.add('is-invalid');
inputParent.classList.remove('is-valid');
input.setAttribute('aria-describedby',inputId+'-error');
} else {
if(document.querySelector('#'+inputId+"-error")){
label_error = document.querySelector('#'+inputId+"-error");
label_error.parentNode.removeChild(label_error);
}
inputParent.classList.remove('is-invalid');
inputParent.classList.add('is-valid');
input.removeAttribute('aria-describedby');
}
}
// On BLUR : check the input blured
inputs.forEach(input => {
input.addEventListener(
"blur", event => {
formCheck(input);
},
false
);
});
// On SUBMIT :
oForm.querySelector('[type="submit"]').addEventListener("click", function(e){
oForm.classList.add('is-submited');
const iLength = inputs.length;
inputs.forEach((input,index) => {
formCheck(input);
if(index >= iLength-1){
const invalidInputs = oForm.querySelectorAll(".is-invalid input, .is-invalid select");
if(invalidInputs.length > 0){
invalidInputs[0].focus();
}
}
input.addEventListener(
"invalid", event => {
event.preventDefault();
},
false
);
});
});
// On RESET :
oForm.querySelector('[type="reset"]').addEventListener("click", function(e){
oForm.classList.remove('is-submited');
inputs.forEach(input => {
let inputParent = input.closest('.form-field');
//inputs[0].focus();
inputParent.classList.remove('is-valid');
inputParent.classList.remove('is-invalid');
});
let msgErrors = document.querySelectorAll('.msg-form-error');
msgErrors.forEach(msgError => {
msgError.parentNode.removeChild(msgError);
});
});






