Highlighter: A MooTools Search & Highlight Plugin

By  on  

Searching within the page is a major browser functionality, but what if we could code a search box in JavaScript that would do the same thing? I set out to do that using MooTools and ended up with a pretty decent solution.

The MooTools JavaScript Class

var Highlighter = new Class({
	/* implements */
	Implements: [Options],

	/* options */
	options: {
		autoUnhighlight: true,
		caseSensitive: false,
		elements: '*',
		className: '',
		onlyWords: false,
		tag: 'span'
	/* initialization */
	initialize: function(options) {
		/* set options */
		this.elements = $$(this.options.elements);
		this.words = [];
	/* directs the plugin to highlight elements */
	highlight: function(words,elements,className) {
		/* figure out what we need to use as element(s) */
		var elements = $$(elements || this.elements);
		var klass = className || this.options.className;
		if (words.constructor === String) { words = [words]; }
		/* auto unhighlight old words? */
		if(this.options.autoUnhighlight) { this.unhighlight(); }
		/* set the pattern and regex */
		var pattern = '(' + words.join('|') + ')';
		pattern = this.options.onlyWords ? '\\b' + pattern + '\\b' : pattern;
		var regex = new RegExp(pattern, this.options.caseSensitive ? '' : 'i');
		/* run it for each element! */
		elements.each(function(el) { this.recurse(el,regex,klass); },this);
		/* make me chainable! */
		return this;
	/* unhighlights items */
	unhighlight: function(words) {
		//var selector = this.options.tag + (word ? '[rel=' + word + ']' : '');
		if (words.constructor === String) { words = [words]; }
		words.each(function(word) {
			word = (this.options.caseSensitive ? word : word.toUpperCase());
			if(this.words[word]) {
				var elements = $$(this.words[word]);
				elements.each(function(el) {
					var tn = document.createTextNode(el.get('text'));
		return this;
	/* recursed function */
	recurse: function(node,regex,klass) {
			if (node.nodeType === 3) {
				var match = node.data.match(regex);
				if (match) {
					/* new element */
					var highlight = new Element(this.options.tag);
					var wordNode = node.splitText(match.index);
					var wordClone = wordNode.cloneNode(true);
					wordNode.parentNode.replaceChild(highlight, wordNode);
					var comparer = highlight.get('text');
					if(!this.options.caseSensitive) { comparer = highlight.get('text').toUpperCase(); }
					if(!this.words[comparer]) { this.words[comparer] = []; }
					return 1;
			} else if ((node.nodeType === 1 && node.childNodes) && !/(script|style)/i.test(node.tagName) && !(node.tagName === this.options.tag.toUpperCase() && node.className === klass)) {
				for (var i = 0; i < node.childNodes.length; i++) {
					i += this.recurse(node.childNodes[i],regex,klass);
			return 0;

The class does provide a few options:

  • autoUnhighlight: (defaults to true) Defines whether or not to auto-unhighlight highlighted words when searched.
  • caseSensitive: (defaults to false) Defines whether the search should be case sensitive.
  • elements: (defaults to '*') Defines which elements are searchable.
  • className: (defaults to '') The class name that will represent the highlighted word class. Gets applied to a span.
  • onlyWords: (defaults to false) Defines whether the class should only find words.
  • tag: (defaults to 'span') Defines the generated element type which will contain the highlighted text.

The class has two main methods:

  • highlight: Highlights the given text. Accepts the words, elements, and classname as parameters.
  • unhighlight: Unhighlights the given text. Accepts words as parameters.

The MooTools Usage

/* sample usage */
window.addEvent('domready',function() {
	/* instance */
	var highlighter = new Highlighter({
		elements: '#sample-content li',
		className: 'highlight',
		autoUnhighlight: false
	/* submit listener */
	document.id('submit').addEvent('click',function() { if(document.id('search').value) { highlighter.highlight(document.id('search').value); } });
	document.id('submit3').addEvent('click',function() { if(document.id('search3').value) { highlighter.highlight(document.id('search3').value,'*','highlight1'); } });
	document.id('submit2').addEvent('click',function() { if(document.id('search2').value) { highlighter.unhighlight(document.id('search2').value); } });
	document.id('search').addEvent('keypress',function(e) { if(e.key == 'enter') { document.id('submit').fireEvent('click'); } });
	document.id('search3').addEvent('keypress',function(e) { if(e.key == 'enter') { document.id('submit3').fireEvent('click'); } });
	document.id('search2').addEvent('keypress',function(e) { if(e.key == 'enter') { document.id('submit2').fireEvent('click'); } });

What's great is that there are only two functions to use publicly for this class: highlight() and unhighlight().

It's important for me to mention that this class is not perfect! One glaring issue is that if you search for a word, then unhighlight the word, and then look for that word with the next word ("Lorem" => "Lorem ipsum"), the searcher doesn't find the second word due to the way the nodes are in place. If you have a solution to fix that, please let me know. This class was based on http://bartaz.github.com/sandbox.js/jquery.highlight.html.

Happy searching!


Recent Features

  • By
    9 Mind-Blowing WebGL Demos

    As much as developers now loathe Flash, we're still playing a bit of catch up to natively duplicate the animation capabilities that Adobe's old technology provided us.  Of course we have canvas, an awesome technology, one which I highlighted 9 mind-blowing demos.  Another technology available...

  • By
    Responsive and Infinitely Scalable JS Animations

    Back in late 2012 it was not easy to find open source projects using requestAnimationFrame() - this is the hook that allows Javascript code to synchronize with a web browser's native paint loop. Animations using this method can run at 60 fps and deliver fantastic...

Incredible Demos

  • By
    TextboxList for MooTools and jQuery by Guillermo Rauch

    I'll be honest with you: I still haven't figured out if I like my MooTools teammate Guillermo Rauch. He's got a lot stacked up against him. He's from Argentina so I get IM'ed about 10 times a day about how great Lionel...

  • By
    Introducing MooTools Dotter

    It's best practice to provide an indicator of some sort when performing an AJAX request or processing that takes place in the background. Since the dawn of AJAX, we've been using colorful spinners and imagery as indicators. While I enjoy those images, I am...


  1. pretty slick ;)

  2. tlx

    Really cool!

  3. Alexander


  4. To get rid of the “unhighlight/repeat search” issue, you can just scrub out the highlight class, i.e.


    at the start of a search.

  5. i love jquery.


  6. Hi David,

    your script is really fantastic, but there is an error on it. If the string don’t match in every letters the highlight doesn’t work. Eg.: Lorem Ipsum. If I write Lore Ipsun, or Ipsun, Loren, etc. Don’t return the letters matched. Right? The scripts was that way, or it is an error?

  7. rodreego: That’s a known shortcoming of the script…so far. I’ll be looking to improve it soon.

  8. emse

    hey david
    how can I combine this script with a smoothscroll? I’m an absolute beginner with mootools

  9. What would you be trying to SmoothScroll to? The functionalities are different.

  10. emse

    i have a large page where every item is posted once. i want the user to type e.g. “Nightwish” and the script should find the word and scroll down to it (and highlight)

  11. I see. You’ll need to implement Events on the class — I’d recommend an “onFind” event that gets fired when a match is found. Then you can direct the element to be scrolled to.

  12. witold

    hi, i use the following cod to highlight / unhighlight searched word by clicking on a checkbox:

    $('colorme').addEvent('change',function() { 
    if($('colorme').checked==true) { 
    highlighter.highlight(Cookie.read('search_value'),'*','highlight');	} 
    else { highlighter.unhighlight(Cookie.read('search_value')); }

    for some reason i get the following error

    el.getParent() is null

    can you tell me what’s wrong

    regards, witold

  13. this information most important for me.

  14. this seems like a great plugin, judging by the demo, but I just can’t get it working… if I use autoUnhighlight: true, when trying to search I always get the error

    words is undefined


    if (words.constructor === String) { words = [words]; }

    which is in the unhighlight function…

    in any case, it won’t even search and I don’t think I do anything wrong…

  15. Katie

    Is there any way for the code to unhighlight the old search automatically when a new search is done?

  16. mrazi

    Hi David,

    this can fix the problem when searching for a word with another word after unhighligting itself.

         elements.each(function(el) {
               var tn = document.createTextNode(el.get('text'));
               tn.parentNode.normalize(); //add this line

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!