How to Add a Phone Number Mask to the Billing Address Phone Field in WooCommerce Blocks Checkout

If you’re using the modern WooCommerce checkout built with Gutenberg blocks, you may have noticed that customizing form fields is a bit trickier than it was with the classic shortcode-based checkout. One common request is to apply a phone number input mask, such as formatting input as (123) 456-7890 while the user types.

In this article, we’ll walk you through how to implement a working phone number mask in the WooCommerce Blocks checkout that works for both guest and logged-in users, and avoids common pitfalls like values being reset or the script not initializing properly.


⚠️ The Problem

When using WooCommerce Blocks, fields like the billing phone number are rendered and managed by React. This means:

  • Custom JavaScript that manipulates the field might run before the field exists.
  • Even if you apply a mask, WooCommerce might overwrite your changes when the form updates.
  • Using libraries like jquery.mask can result in fields not behaving correctly or resetting on blur.

This makes it challenging to provide a consistent user experience for formatting phone numbers.


✅ The Goal

We want the #billing-phone field to:

  • Automatically format input into the format (123) 456-7890
  • Work for both logged-in users and guests
  • Be persistent even after WooCommerce re-renders the form
  • Avoid triggering infinite loops or console errors

📄 The Solution

We use a small JavaScript snippet embedded via PHP in your theme or custom plugin. This snippet:

  1. Waits for the #billing-phone field to appear
  2. Adds a custom input mask using native JavaScript
  3. Formats the phone number while typing
  4. Dispatches input and change events so React respects the updated value
  5. Prevents infinite loops by checking if the value is already formatted

Here’s the full working code:

PHP
add_action( 'wp_enqueue_scripts', 'mask_checkout_phone_number' );
function mask_checkout_phone_number() {
    if ( is_checkout() ) {
        wp_add_inline_script(
            'wp-hooks',
            'document.addEventListener("DOMContentLoaded", function () {
                function formatPhoneNumber(value) {
                    const digits = value.replace(/\D/g, "").substring(0, 10);
                    const parts = [];
                    if (digits.length > 0) parts.push("(" + digits.substring(0, 3));
                    if (digits.length >= 4) parts.push(") " + digits.substring(3, 6));
                    if (digits.length >= 7) parts.push("-" + digits.substring(6, 10));
                    return parts.join("");
                }

                function updateReactInputValue(el, newValue) {
                    if (el.value === newValue) return;
                    el.value = newValue;
                    el.dispatchEvent(new Event("input", { bubbles: true }));
                    el.dispatchEvent(new Event("change", { bubbles: true }));
                }

                function attachMask(input) {
                    if (!input || input.dataset.masked) return;
                    input.addEventListener("input", function (e) {
                        const formatted = formatPhoneNumber(e.target.value);
                        updateReactInputValue(e.target, formatted);
                    });
                    input.dataset.masked = "true";
                }

                function observePhoneInput() {
                    const input = document.querySelector("#billing-phone");
                    if (input) attachMask(input);
                }

                observePhoneInput();
                const observer = new MutationObserver(() => observePhoneInput());
                observer.observe(document.body, { childList: true, subtree: true });
            });'
        );
    }
}

🎮 Why This Works

  • The MutationObserver makes sure the script adapts to React rerenders
  • Formatting happens only when needed (avoids RangeError)
  • Events are bubbled properly so WooCommerce Blocks accepts the value

📊 Result

Now, when your customers enter a phone number at checkout, they see it automatically formatted as (123) 456-7890. This works smoothly across all user types and device types.


📣 Final Notes

  • Make sure the id of your phone field is billing-phone. This is standard for WooCommerce Blocks.
  • If you’re using additional validation or localization, you can enhance the script further (e.g., international formats).
  • This approach keeps your checkout JavaScript-light and React-compatible.

Let us know in the comments if you’d like to see versions for other fields or country-specific formats!


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *