Search code examples
javascriptreplaceinnerhtml

innerHTML not rendering after replace


I am trying to get certain words to highlight in a page. To accomplish this, I want to find all text nodes and replace only the specific word with a span that will highlight it. The code appears to search and find the words in the text nodes properly, but the replace is not working. I get this:

<span style="background-color: #FBC300;">foo</span>

And I want to get this:
foo (with a highlighted background)

function toRegExp(text) {
    return new RegExp(text, 'g');
}

function toSpan(text) {
    return '&lt;span style="background-color: #FBC300;"&gt;' + text + '&lt;/span&gt;';
}

function replaceText(squery, node) {
    node = node || document.getElementById("mainContent"); // base node

  for (node=node.firstChild;node;node=node.nextSibling){
    if (node.nodeType==3) {
        if (node.innerHTML) {
            node.innerHTML = node.innerHTML.replace(toRegExp(squery), toSpan(squery));
          } else { // support to IE
            node.nodeValue = node.nodeValue.replace(toRegExp(squery), toSpan(squery));
          }
    }
    else replaceText(squery, node);
  }
}

Solution

  • A text node can't contain elements, so you'll need to take the text node and split it into multiple nodes. For example, if you want to highlight world in hello world, you'll need to split it into a text node hello and an element <span>world</span>, which you can then style. Something like this:

    function replaceText(squery, node) {
        node = node || document.getElementById("mainContent"); // base node
    
        for (node = node.firstChild; node; node=node.nextSibling) {
            if (node.nodeType == 3 && node.nodeValue) {
                var pieces = node.nodeValue.split(squery);
                if (pieces.length > 1) {
                    // Split this node up into pieces
                    for (var i = 0; i < pieces.length - 1; i++) {
                        node.parentNode.insertBefore(document.createTextNode(pieces[i]), node);
    
                        var span = document.createElement('span');
                        span.style.backgroundColor = '#FBC300';
                        span.innerText = squery;
                        node.parentNode.insertBefore(span, node);
                    }
                    node.nodeValue = pieces[pieces.length - 1];
                }
            }
            else
                replaceText(squery, node);
        }
    }