skip to Main Content
<div class="formRow">
    <label for="phone">Phone number</label>
    <input name="custPhone" id="phone" type="tel" placeholder="(nnn) nnn-nnnn" 
     pattern="^d{10}$|^((d{3})s*)?d{3}[s-]?d{4}$" > 
</div>

This comes from a textbook (albeit a few years old) and I don’t know why the browser just accepts anything.

Can anyone see what might be preventing the regex from doing its job to get 7 or 10 digit phone numbers to be validated and other patterns to be rejected?

When I take just the expression and test at regex101.com, the expression seems to do its job there.

^d{10}$|^((d{3})s*)?d{3}[s-]?d{4}$

On regex101.com 1234567 will match and 1234567890 will match and other patterns with fewer than 7, more than 10 and patterns with 8, and 9 digits will be rejected.

The textbook’s other regex validation is fine.
It doesn’t seem to be related to the browser as it fails with two different browsers.

I’m stumped.

2

Answers


  1. From documentation:

    In the case of pattern attribute, we are matching against the entire value, not just any subset, as if a ^(?: were implied at the start of the pattern and )$ at the end.

    This means your actual pattern is ^(?:^d{10}$|^((d{3})s*)?d{3}[s-]?d{4}$)$ – browser explicitly adds start and end symbols, so your RegEx becomes invalid.


    What you can do here is to validate form via JS:

    const phoneInput = document.getElementById("phone");
    
    phoneInput.addEventListener("input", (event) => {
      if (!/^d{10}$|^((d{3})s*)?d{3}[s-]?d{4}$/.test(phoneInput.value)) {
        phoneInput.setCustomValidity("Invalid format.");
      } else {
        phoneInput.setCustomValidity("");
      }
    
      phoneInput.reportValidity();
    });
    input:invalid {
        border: 1px solid red;
    }
    <form class="formRow">
        <label for="phone">Phone number</label>
        <input name="custPhone" id="phone" type="tel" placeholder="(nnn) nnn-nnnn"> 
    </form>
    Login or Signup to reply.
  2. The value provided to a pattern attribute is converted into a regular expression with the v flag for unicode sets.

    The HTML standard defines that:

    The compiled pattern regular expression of an input element, if it exists, is a JavaScript RegExp object. It is determined as follows:

    1. If the element does not have a pattern attribute specified, then return nothing. The element has no compiled pattern regular expression.

    2. Let pattern be the value of the pattern attribute of the element.

    3. Let regexpCompletion be RegExpCreate(pattern, "v").

    4. If regexpCompletion is an abrupt completion, then return nothing. The element has no compiled pattern regular expression.

    5. Let anchoredPattern be the string "^(?:", followed by pattern, followed by ")$".

    6. Return ! RegExpCreate(anchoredPattern, "v").

    In v / unicode sets mode, it is mandatory to escape a single dash inside a character class even if it is next to a bracket. Demo:

    const nonV = new RegExp(/[a-]/);
    
    console.log('nonV match "a"', nonV.test("a"));
    console.log('nonV match "-"', nonV.test("-"));
    console.log('nonV match "b"', nonV.test("b"));
    
    try {
      const v = new RegExp(/[a-]/, "v"); // throws an error
    
      console.log('v match "a"', v.test("a"));
      console.log('v match "-"', v.test("-"));
      console.log('v match "-"', v.test("b"));
      
    } catch (error) {
      console.error("cannot use unescaped dash:", error.message)
    }
    
    const vEscaped = new RegExp(/[a-]/, "v");
    
    console.log('vEscaped match "a"', vEscaped.test("a"));
    console.log('vEscaped match "-"', vEscaped.test("-"));
    console.log('vEscaped match "b"', vEscaped.test("b"));
    .as-console-wrapper { max-height: 100% !important }

    Therefore, the - in [s-] needs to be escaped in HTML:

    :invalid {
      background-color: red;
      color: white;
    }
    <div class="formRow">
        <label for="phone">Phone number</label>
        <input name="custPhone" id="phone" type="tel" placeholder="(nnn) nnn-nnnn" 
         pattern="^d{10}$|^((d{3})s*)?d{3}[s-]?d{4}$" > 
    </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search