Web & Software Developer

Custom Browser Validity Message With HTML Instead of Just Text – WooCommerce Example

Normally, the browser’s HTML5 constraint validation API allows us to set a custom message with setCustomValidity(). However, that only allows text, no HTML. This example shows you how to add an HTML link to the custom validity error message.

This example is specifically for the WooCommerce product quantity input field, and it specifically adds a custom message when the quantity entered exceeds the max allowed. You can modify this, as needed.

The basic method is this:

  1. Stop the built-in browser form validation for the Add to cart form.
  2. Add your own custom JavaScript validation for the quantity input field.
  3. Create your own custom error message to show if validation fails. This allows you to add HTML to the error message. This custom message will have to be styled, so I’ve added some CSS styles on lines 158–163.

You must edit the error message on line 34 to suit your needs. In this example, the error message is:

Limit of {MAX-NUMBER} per order. Please go here.

…in which “go here” is a link.

The HTML for the link on line 34 looks like this:

<a href=\'#\'>go here</a>
  • Change the # to the URL address of the page which you want to link to. Leave the backslashes and single quotes as they are.
  • Change go here to the text for the link.

Here is the entire code, and it goes in your functions.

 * Customize the browser's default constraint validation message for exceeding the input max
function isa_wc_max_qty_custom_html_error_msg() {
    /* Add JS to frontend wherever woocommerce.js is loaded. */
    wp_add_inline_script( 'woocommerce', 'window.onload = function(){
 		var productForm = document.querySelector( "form.cart" );
		var cartForm = document.querySelector( "form.woocommerce-cart-form" );

		// Custom validation for the quantity field

		var qtyHasError = function (field) {

		    // Get validity
		    var validity = field.validity;

		    // If valid, return null
		    if (validity.valid) return;

		    // If number input isn"t a number
		    if (validity.badInput) return "Please enter a number.";

		    // If a number value doesn"t match the step interval
		    if (validity.stepMismatch) return "Please select a valid value.";

		    // If a number field is over the max
		    if (validity.rangeOverflow) {

		    	var max = field.getAttribute( "max" );

		    	return "Limit of " + max + " per order. Please <a href=\'#\'>go here</a>.";


		    // If a number field is below the min
		    if (validity.rangeUnderflow) return "Please select a value that is no less than " + field.getAttribute("min") + ".";

		    // If all else fails, return a generic catchall error
		    return "The value you entered for this field is invalid.";


		// Show the error message

		var qtyShowError = function (field, error) {

		    // Add error class to field

		    // Get field id or name
		    var id = field.id || field.name;
		    if (!id) return;

		    // Check if error message field already exists
		    // If not, create one
		    var message = field.form.querySelector(".qty-error-message#error-for-" + id );
		    if (!message) {
		        message = document.createElement("div");
		        message.className = "qty-error-message";
		        message.id = "error-for-" + id;
		        field.parentNode.insertBefore( message, field.nextSibling );

		    // Add ARIA role to the field
		    field.setAttribute("aria-describedby", "error-for-" + id);

		    // Update error message
		    message.innerHTML = error;

		    // Show error message
		    message.style.display = "block";
		    message.style.visibility = "visible";


		// Remove the error message

		var qtyRemoveError = function (field) {

		    // Remove error class to field

		    // Remove ARIA role from the field

		    // Get field id or name
		    var id = field.id || field.name;
		    if (!id) return;

		    // Check if an error message is in the DOM
		    var message = field.form.querySelector(".qty-error-message#error-for-" + id + "");
		    if (!message) return;

		    // If so, hide it
		    message.innerHTML = "";
		    message.style.display = "none";
		    message.style.visibility = "hidden";


		// Validate the quantity field

        function validateQtyonBlur( event ) {
			// Validate the field
			var error = qtyHasError(event.target);

			// If there is an error, show it
			if (error) {
				qtyShowError(event.target, error);

			// Otherwise, remove any existing error message


		if ( productForm ) {

			// Stop the built-in browser form validation for Add to Cart form
			productForm.setAttribute("novalidate", true);

			// If there is an error, do not submit form
			productForm.addEventListener("submit", function (event) {
			    if ( qtyHasError( event.target.quantity ) ) {
			}, false);

		// Stop the built-in browser form validation for Update Cart form
		if ( cartForm ) {
			cartForm.setAttribute("novalidate", true);

		// Do custom validation on quantity field
        var quantity = document.querySelector( "form.cart .qty" );
        var cartQuantity = document.querySelector( "form.woocommerce-cart-form .qty" );
        if ( quantity ) { // quantity input on single product page
            quantity.addEventListener( "blur", validateQtyonBlur, true );
        if ( cartQuantity ) { // quantity input on cart page
            cartQuantity.addEventListener( "blur", validateQtyonBlur, true );


	/* Add CSS to frontend wherever woocommerce.js is loaded. */
    wp_add_inline_style( 'woocommerce-layout', '

		.qty-error-message {
			border:1px solid #D8000C;
			border-radius: 5px;
	' );

add_action( 'wp_enqueue_scripts', 'isa_wc_max_qty_custom_html_error_msg', 9999 );


Questions and Comments are Welcome

Your email address will not be published. All comments will be moderated.

Please wrap code in "code" bracket tags like this: