Last week, I wrote “Adding Search to Your Site With JavaScript” over on David Walsh’s blog. It covered the basics of how we added search to the TrackJS Docs Site with client-side JavaScript and how to serialize out the page data with Jekyll.

But our JavaScript search can do so much more! Let’s continue our search example to add relevant result snippets and search term highlighting.

Search Snippets

When we left off, we were rendering our search results using the page title and the first 200 characters of the page. That’s pretty niave, as it doesn’t provide any context to the user if the search term doesn’t appear in those first 200 characters. Instead, we should look for the search term in the content string and show it in context. We should probably give it some emphasis too, so the user can see their search term stand out in the results.

That can get a bit complex, so let’s replace the r.content.substring(0, 200) call while rendering results in search.js to call a new function, formatContent(r.content, searchTerm). Here’s what that looks like:

function formatContent(content, searchTerm) {
    var termIdx = content.toLowerCase().indexOf(searchTerm.toLowerCase());
    if (termIdx >= 0) {
        var startIdx = Math.max(0, termIdx - 140);
        var endIdx = Math.min(content.length, termIdx + searchTerm.length + 140);
        var trimmedContent = (startIdx === 0) ? "" : "…";
        trimmedContent += content.substring(startIdx, endIdx);
        trimmedContent += (endIdx >= content.length) ? "" : "…"

        var highlightedContent = trimmedContent.replace(new RegExp(searchTerm, "ig"), function matcher(match) {
            return "<strong>" + match + "</strong>";
        });

        return highlightedContent;
    }
    else {
        var emptyTrimmedString = content.substr(0, 280);
        emptyTrimmedString += (content.length < 280) ? "" : "&hellip;";
        return emptyTrimmedString;
    }
}

Now we’ll find the searchTerm in the context string and displays the 140 characters before and after. It also handles whether we should add ellipsis to either end and surrounds all the occurrences of the searchTerm in <strong> tags so they’ll pop.

Search Highlighting

Now the user knows what result is most relevant to their search, but clicking on a result isn’t the best experience. The user is dropped at the top of the page with no context about what they searched for or where it’s located in the page. It’d be great if we could highlight the occurrences of their search in the page and scroll the page to where we find a match.

To make that happen, we’ll need to tell the rest of the site that the user clicked on a search result to land on the page. If you notice from “Rendering the Results” in Part 1, we’re building the links to each search result with an additional querystring parameter, ?q=%searchTerm%.

Now, we can write some code to look for this in our site, and highlight the specified term. The user can land on any page in the site from the search result, so we need to add our highlighter somewhere global. For the TrackJS Docs, I put it in our main.js file.

var searchTerm = getQueryVariable("q");
if (searchTerm) {
    findAndReplaceDOMText(article, {
        find: new RegExp(searchTerm, "ig"),
        wrap: "span",
        wrapClass: "highlight"
    });
    var highlights = document.querySelectorAll(".highlight");
    if (highlights[0]) {
        highlights[0].scrollIntoView(true);
    }
}

Wait, where did that findAndReplaceDOMText come from? That’s another handy little library that simplifies the logic of crawling the DOM tree. You can find findAndReplaceDOMText online at GitHub.

With this last step in place, the user can search our documentation, see relevant search results, and go directly to a highlighted page where their search term is visible. All this without any server-side code, and very lightweight client-side JavaScript. Even though we’ve limited our use of JavaScript with this solution, we still need to watch it for bugs. TrackJS can help with that, grab your free trial of the best error monitoring service available today, and make sure your JavaScript keeps working great.