Set custom native input validity message

setCustomValidity example

by moob

HTML

<form>
  <fieldset>
    <legend>
      Tries to submit on key
    </legend>
    <label>
            This example needs a valid email address and won't allow '[email protected]'.
        </label>
    <input type="email" placeholder="[email protected]" required="required" pattern="^(([email protected]).)*$" data-validity-msg="What the fuck are you playing at?" />
    <input type="text" placeholder="not required text" />
    <input type="text" placeholder="is required text" required="required" pattern="^[a-zA-Z]{4}$" />
    <input type="submit" />
  </fieldset>
</form>

CSS

input {
  border: 1px solid grey;
  outline: none;
}

input:invalid {
  border-color: red;
}

input:valid {
  border-color: green;
}

input:invalid~input:invalid {
  opacity: 0.2;
  pointer-events: none;
}

input:valid~input {
  opacity: 1;
  pointer-events: inherit;
}

JavaScript

var inputs = document.querySelectorAll("input");
var submit = document.querySelector("input[type=submit]");
var form = document.querySelector("form");
var defaultMsg = "Erm, that's wrong somehow!"; //default custom message if no data-validity-msg attr

// forEach method
var forEach = function(array, callback, scope) {
  for (var i = 0; i < array.length; i++) {
    callback.call(scope, i, array[i]); // passes back stuff we need
  }
};

// setCustomValidity method
var setCustomValidity = function(el, index) {
  //setCustomValidity works in modern browsers >= IE11
  el.setCustomValidity(""); //assume valid
  var customMsg = el.getAttribute("data-validity-msg") || defaultMsg; //
  if (!el.checkValidity()) {
    el.setCustomValidity(customMsg);
    submit.click(); //trigger a click to see the custom message
  } else {
    el.setCustomValidity(""); //empty it
  }
}

forEach(inputs, function(index, el) {
  el.onkeyup = function() {
    setCustomValidity(this);
  }
});