Highlight Keywords on Page with jQuery

By Hawkee on Feb 21, 2013

This will take a string of keywords and wrap a highlight span around each word. It takes two inputs: keywords and element:

keywords: The keywords to be highlighted.
element: Where we are looking for the keywords. This element can be a repeated element.

function highlight_words(keywords, element) {
    if(keywords) {
        var textNodes;
        keywords = keywords.replace(/\W/g, '');
        var str = keywords.split(" ");
        $(str).each(function() {
            var term = this;
            var textNodes = $(element).contents().filter(function() { return this.nodeType === 3 });
            textNodes.each(function() {
              var content = $(this).text();
              var regex = new RegExp(term, "gi");
              content = content.replace(regex, '<span class="highlight">' + term + '</span>');
              $(this).replaceWith(content);
            });
        });
    }
}

You can simply bold the keywords or do what you'd like with this CSS:

.highlight {
    font-weight: bold;
}

We use this here at Hawkee.com for our search function.

Comments

Sign in to comment.
Sparky2019   -  Dec 19, 2019

Sweet little piece of code!! I have already added it to my site. A slight problem I found during 'testing' though...

keywords = keywords.replace(/\W/g, ''); // removes any spaces
var str = keywords.split(" "); // uses spaces to split

If you want to separate the keywords string by finding 'spaces' (which is what the second line does), remove the first line.

Sparky2019  -  Dec 19, 2019

Just a few little mods. If you want the highlighted text to be CaSe sEnsitiVe, and want to display a count of what is found, here is my little addition :)

function highlight_words(keywords, element) {
    if(keywords) {
        var st1 = 0; // for count
        var textNodes;
        var keywords;
        var str = keywords.split(" ");
        $(str).each(function() {
            var term = this;
            var textNodes = $(element).contents().filter(function() { return this.nodeType === 3 });
            textNodes.each(function() { 
                var content = $(this).text();
                var regex = new RegExp(term, "gi");
                var count = (content.match(regex) || []).length; // for count
                content = content.replace(regex, function(match) { // for case sensitive :)
                    return '<span class="highlight">' + matchCase(term, match) + '</span>';
                });
                $(this).replaceWith(content);
                st1=st1+count; // for count
            });
        });
        $('#st1').html(st1); // populates your count span/div
    }
}
function matchCase(text, pattern) {
    var result = '';
    for(var i = 0; i < text.length; i++) {
        var c = text.charAt(i);
        var p = pattern.charCodeAt(i);
        if(p >= 65 && p < 65 + 26) {
            result += c.toUpperCase();
        } else {
            result += c.toLowerCase();
        }
    }
    return result;
}
Sign in to comment

sean   -  May 22, 2013

Great snippet! However, I might have made this a jQuery plugin instead (since we're in the jQuery section :P). This way you could chain the element while offering other (future) parameters. Consider the following implementation:

$('element').highlightWords({
  words: ['keyword1', 'keyword2'],
  effect: 'fadeIn'
});

Is there a reason you decided against that route?

Hawkee  -  May 22, 2013

Good idea! It was really just a quick feature-add, so I didn't flesh it out as much as you suggested. I might just do that if I come back around to working on this again.

diegotucholga  -  Mar 30, 2016

No need for this function anymore. There's a plugin with much more options: mark.js
(Github: https://github.com/julmot/mark.js)

Sign in to comment

Are you sure you want to unfollow this person?
Are you sure you want to delete this?
Click "Unsubscribe" to stop receiving notices pertaining to this post.
Click "Subscribe" to resume notices pertaining to this post.