Skip to content
Advertisement

innerText is different in a cloned node

(NOTE: This question isn’t the same as the similar one above, as it is about differences between attached and detached DOM trees.)

A simple bit of HTML containing a DIV with no whitespace between its elements:

<!DOCTYPE html>
<html>

  <body>
    <div><h1>The Title</h1><p>A paragraph.</p><p>A second paragraph.</p></div>
  </body>

  <script type="text/javascript">

   const div = document.querySelector("div");

   console.log(div.innerText);

   const clone = div.cloneNode(true);
   console.log(clone.innerText);

   document.body.appendChild(clone);
   console.log(clone.innerText);

  </script>
</html>

I output innerText to the console three times.

The first time is that of the original DIV:

The Title

A paragraph.

A second paragraph.

The second is that of the cloned DIV, which I would expect to be the same, but is:

The TitleA paragraph.A second paragraph.​

The third is again that of the cloned DIV, but after it has been added to the document, now what I would expect it to be:

The Title

A paragraph.

A second paragraph.

Why is the spacing different when it is not part of the document?

Advertisement

Answer

This is a quirk of innerText for detached DOM nodes:

If the element itself is not being rendered (for example, is detached from the document or is hidden from view), the returned value is the same as the Node.textContent property.

This is because innerText takes CSS into account (in this case, the display: block properties of the tags to insert new lines (n)).

From the algorithm for computing innerText, step 9 says:

If node’s used value of ‘display’ is block-level or ‘table-caption’, then append 1 (a required line break count) at the beginning and end of items.

As you see, after you insert the cloned node into the DOM, then innerText returns what the original node did because it is able to compute those CSS properties:

const div = document.querySelector("div");

console.log("Original, innerText:", JSON.stringify(div.innerText));
console.log("Original, textContent:", JSON.stringify(div.textContent));

const clone = div.cloneNode(true);
console.log("Detached clone, innerText:", JSON.stringify(clone.innerText));
console.log("Detached clone, textContent:", JSON.stringify(clone.textContent));

document.body.appendChild(clone);

console.log("Attached clone, innerText:", JSON.stringify(clone.innerText));
console.log("Attached clone, textContent:", JSON.stringify(clone.textContent));
<div><h1>The Title</h1><p>A paragraph.</p><p>A second paragraph.</p></div>
User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement