How to add style for specific words at HTML using JavaScript?

Viewed 913

Could someone help me to write JS function which will take a string(word) as an argument? And then add an additional style (change color for example) for all these words in the HTML. I don't know where it is located. This "word" can be inside <div>, or <p> or even <b>.

Example:

HTML:

<p id="p1">Hello World!</p>
<div>Hello World!</div>

function Change(string word){
  //change font color to red
}

Call function:

Change("Hello")

Result:

All of the "Hello" words in the HTML have red font color.

By the way, is it possible to write something like this?

4 Answers

Here is a method that will find the word and replace it with a <span class='red'> word </span>. I have set upa class called 'red' with the style. This is very rudimentary, but works for simple applications. There are explanations in the comments below

function Change(word) {
  //find all html elements on the page inside the body tag
  let elems = document.querySelectorAll("body *");
  // get our replacement ready
  let span = "<span class='red'>" + word + "</span>";
  //loop through all the elements
  for (let x = 0; x < elems.length; x++) {
    // for each element, 'split' by the word we're looking for, then 'join' it back with the replacement
    elems[x].innerHTML = elems[x].innerHTML.split(word).join(span);
  }
}

Change('Hello');
.red {
  color: red;
}
<p id="p1">Hello World!</p>
<div>Hello World!</div>

CSS is made for styling. Use JS to add the class to your HTML element.

The Function:

Pass the string to search for and the selector/s to search, in my case I am searching all tags in the DOM and returning an array [...document.getElementsByTagName('*')].

We define an array to hold the non-restricted elements we want to search and another that holds the restricted tags we want to skip. We then loop the output array with !restricted.includes(tag.nodeName.toLowerCase(), this checks to see if our restricted array does not include an element from our DOM query. For the elements that return true, we push them into our output array --> output.push(tag)

Once we have our output array filled with the tags we want to search, we search the tag for our string --> tag.innerText.includes(string) and VERY IMPORTANT: !(tag.textContent.match(/\n/g)||[]).length will make sure it is the right child node, if this returns true, we replace the tags innerHTML and simply wrap our string with span tags that now contain a class that is styled as we want it to be styled -->

tag.innerHTML = tag.innerText.replace(string, `<span class="red">${string}</span>`)

const els = [...document.getElementsByTagName('*')]
const string = "Hello"

function Change(string, els) {
  const restricted = ['html', 'body', 'head', 'style', 'meta', 'script']
  const output = []
  els.forEach(tag => !restricted.includes(tag.nodeName.toLowerCase()) ? output.push(tag) : null)
  output.forEach(tag => tag.innerText.includes(string) && !(tag.textContent.match(/\n/g) || []).length ? tag.innerHTML = tag.innerText.replace(string, `<span class="red">${string}</span>`) : null)
}

Change(string, els)
.red {
  color: red;
}
<p id="p1">Hello World!</p>
<div>Hello World...</div>

<div>
  <ul>
    <li>Hello World.</li>
  </ul>
</div>

<p>
  <a href="#">Hello <span>World</span></a>
</p>

<table border="1">
<tr>
  <th>Hello</th><th>World</th>
  </tr>
<tr>
  <td>World</td><td>Hello</td>
  </tr>
</table>

Here's a really basic example. Note that while this is case insensitive, it will replace all occurrences with whatever case you provide. For example, in the block below I put in "Hello", which sets the one occurrence of hello to Hello. You could of course remove the i in the regex's flags to make it case sensitive again, but you'd have to run the function twice with both cases to highlight both instances.

function color(str, color)
{
  var rx = new RegExp(str, "ig");
  var replaced = document.body.innerHTML.replaceAll(rx, "<span style='color:"+color+"'>"+str+"</span>");
  document.body.innerHTML = replaced;
}

color("Hello", "red");
<p>Hello world</p>
<p>This block contains the word "hello."</p>

This is the best solution. It works fine at any html, just call matchText("text","black","red");

function replaceInElement(element, find, replace) {
    for (let i= element.childNodes.length; i-->0;) { 
        let child= element.childNodes[i];
        
        if (child.nodeType==1) { 
            let tag= child.nodeName.toLowerCase();  
            if (tag!='style' && tag!='script') 
                replaceInElement(child, find, replace); 
        } else if (child.nodeType==3) { 
            replaceInText(child, find, replace);
        }
    }
}
function replaceInText(text, find, replace) {
    let match; 
    let matches= [];
    
    while (match= find.exec(text.data)){ 
        matches.push(match);
    }
    
    console.log(matches);
    for (let i= matches.length; i-->0;) {
        match = matches[i];

        text.splitText(match.index); 
        text.nextSibling.splitText(match[0].length);

        text.parentNode.replaceChild(replace(match), text.nextSibling); 
    }
}

let matchText = (word, backColor, textColor) => {
    let regexp = new RegExp(`\\b(${word})\\b`, 'gmi');

    replaceInElement(document.body, regexp, function(match) { 

        var elem= document.createElement('span'); 
        elem.style.backgroundColor = backColor;
        elem.style.color = textColor;

        elem.appendChild(document.createTextNode(match[0]));
        return elem;
    });
}
Related