Auto-selecting navigation
June 17th, 2006This article offers an alternative to the laborious task of coding up which <li> or <a> navigation tags need the 'selected' class (or however you concoct the solution).
The Problem
Any web developer, or designer that wants to offer some visual indication which page the we are on, they will probably use a combination of 'selected' and possibly 'unselected' classed on the link or tab.
The developer's task is to ensure that the right link or tab is highlighted when we are viewing the page.
The Old Solution
The way that I have solved this problem in the past (being a developer), either using Perl or PHP, would be to use a hash to track which page is selected, and when I print each link or tab, I would reference the hash with the key value of the current element name.
For example (in PHP, in Perl):
$selected = Array('articles' => ' class="selected"');
foreach ($links as $link)
{
echo '<a href="' . $link->href . '" ' .
$selected[$link->name] . '>' .
$link->name . '</a>';
}
my $selected = { articles => ' class="selected"'};
foreach my $link (@links)
{
print qq{<a href="$link->{'href'}"
$selected->{$link->{'name'}}>$link->{'name'}</a>};
}
The New Solution
The new solution really comes about, because as a developer I really want to avoid doing the dull work, and separating the layout code from the application code is what we all really want to do.
In this solution, you create all the HTML, either through static files, or as you like, and add some JavaScript seasoning to make the the navigation automatically highlight itself.
Prerequisites
- You are happy that when we don't have JavaScript enabled, the navigation doesn't highlight. I justify this by the simple fact as users, we're more interested in the page content, than which page link is highlighted.
- The navigation sits cleanly in one DIV under one ID.
The Code
Notice that this is we've done away with our backend solution altogether.
<h3>Info</h3>
<ul id="sidebar_content">
<li><a href="/info/news">News</a></li>
<li><a href="/info/articles">Articles</a></li>
<li><a href="/info/resources">Resources</a></li>
<li><a href="/info/about">About</a></li>
</ul>
Now we add our dash of JavaScript spice...
function select_nav() {
var nav_links = document.getElementById('sidebar_content').getElementsByTagName('a');
var selected = location.pathname;
for (var i = 0; i < nav_links.length; i++) {
var link = nav_links[i].pathname;
if (link.substring(0, 1) != '/') link = '/' + link; // fiddle IE's view of the link
if (link == selected) nav_links[i].setAttribute(cattr, 'selected');
}
}
window.onload = function() {
select_nav();
};
...and Bob's your father's brother. The link will automatically select itself.
For those of you using jQuery, here's the same solution, but on a lot less lines (you've got hand it to those jQuery chaps):
$(function(){ if (location.pathname.substring(1))
$('#sidebar_content a[@href$="' + location.pathname.substring(1) + '"]')
.attr('class', 'selected')
});
Updated 25th Sep '06 - with thanks to Kevin, Fallo and Steve.
Note: the a[@href$= part is saying that any anchor tag whose "href" attribute value ends exactly with the string location.pathname.substring(1).
Feel free to add comments, suggestions, ask questions, point out any errors or suggest a better alternative.

Nice solution - very clean, especially in jQuery!
How about changing:
window.onload = function() {
to:
$(document).ready(function() {
in the jQuery version? It seems a little more jQueryish and you don't need to worry about overwriting or being overwritten by any other document.onload scripts (which the current script could do),
Cheers,
Kelvin :)
With the jquery 1.0 +
$(document).ready(function(){
if (location.pathname.substring(1))
$(’#linklist a[@href$=”’ + location.pathname.substring(1) + ’”]’).attr(‘class’, ‘here’);
});
change the .set to .attr
$(document).ready(function(){}) is the same as $(function(){}).
So we can even shorten it further.
$(function(){ if (location.pathname.substring(1)) $(’#linklist a[@href$=â€â€™ + location.pathname.substring(1) + ’â€]’).attr(‘class’, ‘here’);
});
Here is another way:
$(function(){
$(”#menu”).find(“a”).each(function(){
if( location.href.indexOf(this.href) != -1) {
$(this).addClass(“here”);
}
});
});
hello, i have tried your jquery script but it is not working… is it because my links are in this format? Any ideas?
<ul id=”mainmenu”>
<li><a href=”/index.php?page=home”>Home</a></li>
You can actually do this without any JavaScript at all, using only CSS. Roger Johansson has a tutorial.
Hi, I tried the script but it only works with Internet Explorer 7. With other browsers it doesn’t work… That’s right?
@Elisa – to honest I’ve not tried the script in IE 7 yet – but I can confirm that it works in Safari and Firefox. I use it for my own sidebar links and it works fine for me.
Maybe you could post an example?
The method referenced by Adam above using only CSS only works for the top level of navigation. If you have multiple levels that you need highlighting to work for, you’d need to add a lot more css and html to your code.
The method in this tutorial is very elegant. Thanks
The ‘pur CSS solution’ does not separate the content from te layout! Therefore, this way only hides the ‘Old Style Problem’.
Ah! Wonderful, especially since I already had jQuery for sortable tables. Two lines, a little modification to the CSS stylesheet, and BOOM! Thanks a lot!
Well as this JS method being not unobstrusive i don't like this approach and would prefer a pure css solution like Roger Johanssons.
Another question: what if the pathname ends with an anchor tag like #myanchor - will the a href still match the location.pathname?
Here's an idea I was playing with.... I wanted this to work for subpages of a site as well. This pulls of the first folder of the link: (sitename.com/firstfolder/subpage/ would check for firstfolder only)
Hello! Great idea! But how about second and third level menus?
Hi,
I'm new to JQuery but love the simplicity of it and love working with it so far. How would I go about highlighting 2 navigation areas on a page if I have a main and subnav?
hi ,
everybody. I am trying to make work your great script but without success...maybe because I have applied the id to a div tag instead of a ul tag? can you please give me a working demo using javascript? (I have also tried with jquery but nothing changes...)
my attempts can be seen here:
http://www.viabenedicti.it/en
if you click on Places of worship and choose a submenu item it should become red...but the class active is not applied... :( thanx a lot!