Search code examples
javascripthtmlvalidationinnerhtml

HTML Form field validation is bypassed when element is created with .innerHTML


When a form field that has standard HTML validation constraints placed on it (pattern & required in this case) gets inserted into the DOM via the .innerHTML property, the field does not validate. I am aware of the difference between creating an element with .innerHTML and document.createElement() with regards to event registration, but have not encountered this side-effect before.

In my particular situation, there is a very large amount of HTML that must be inserted into the DOM and creating all of it via document.createElement(), then setting all of the node properties and using .appendChild() to establish the proper heirarchy is not desirable.

Why is this and, if it is possible, how can it be overcome (no jQuery answers please)?

NOTE: I am aware of HTML <template>, but since there is no support for it in any version of IE, it won't work for me.

In the snippet below, the first field will work as it should, but the second one demonstrates what I'm talking about. It won't validate if you manually enter data (5 digits in this case) or if you press the button to have valid data be dynamically inserted.

document.querySelector("div").innerHTML = `<input type="text" id="broken" name="zip" pattern="\d{5}" required placeholder="I don't.">`;

document.querySelector("input[type='button']").addEventListener("click", function(){
  document.getElementById("broken").value = "12345";  // 12345 or "12345" - doesn't matter
});
:required { background:#f99; }
:valid    { background:green; }
input[type=text] { width:250px; }
<input type="text" id="zip2" name="zip2" pattern="\d{5}" required placeholder="I work as I should (5 digits please).">
<div></div>
<input type="button" value="Populate">


Solution

  • Missing backslash on your regexp:

    "\\d{5}"
     ^
    

    Look how the backslash disappears:

    console.log(`<input type="text" id="broken" name="zip" pattern="\d{5}" required placeholder="I don't.">`)

    Now everything is working as expected.

    document.querySelector("div").innerHTML = `<input type="text" id="broken" name="zip" pattern="\\d{5}" required placeholder="I don't.">`;   
    
    document.querySelector("input[type='button']").addEventListener("click", function(){
      document.getElementById("broken").value = "12345";  // 12345 or "12345" - doesn't matter
    });
    :required { background:#f99; }
    :valid    { background:green; }
    input[type=text] { width:250px; }
    <input type="text" id="zip2" name="zip2" pattern="\d{5}" required placeholder="I work as I should (5 digits please).">
    <div></div>
    <input type="button" value="Populate">