How to add selected states to your navigation using jQuery.
December 21st, 2009
Here’s a simple jQuery solution for adding selected states to your navigation.
The sample HTML looks like this:
And the sample CSS:
li {
background-color: white;
color: black;
padding: 5px 10px;
}
li.selected {
background-color: black;
color: white;
}
And the corresponding jQuery:
$(document).ready(function() {
// store url for current page as global variable
current_page = document.location.href
// apply selected states depending on current page
if (current_page.match(/home/)) {
$("ul#navigation li:eq(0)").addClass('selected');
} else if (current_page.match(/services/)) {
$("ul#navigation li:eq(1)").addClass('selected');
} else if (current_page.match(/about/)) {
$("ul#navigation li:eq(2)").addClass('selected');
} else if (current_page.match(/information/)) {
$("ul#navigation li:eq(3)").addClass('selected');
} else if (current_page.match(/contact/)) {
$("ul#navigation li:eq(4)").addClass('selected');
} else { // don't mark any nav links as selected
$("ul#navigation li").removeClass('selected');
};
});
How does it work?
First we capture the url of the current page in a variable. Then we use that variable to write conditions based on a regular expression (e.g. if the current url contains the word ‘about’). Finally, we use the :eq(index) selector to target the corresponding <li> and add a class of selected.
The only thing that’s remotely tricky here is the :eq(index) selector. This allows you to use an index to target a specific element within a larger array of matched elements.
So in our example, ul#navigation li would return an array of all five <li> elements whereas ul#navigation li:eq(4) would return only the fifth <li>. This saves us the trouble of having to apply a unique id to each list item.
A few gotchas.
- Make sure your regular expression matchers are not too general or you might end up adding selected states to the wrong pages. For example, this might not be a good solution for a blog where the slugs correspond to post tiles.
- Make sure to include the most recent version of jQuery in your head element.
- Make sure jQuery is loaded before the script for your selected navigation.
- Don’t forget to place your script inside the document ready function. Otherwise your script will run before the DOM is fully loaded – and do nothing.
Tags: jQuery
Hi Cory,
I’ve had to do this before myself, when a server-side solution (which is by far preferable) was unavailable. Rather than create a separate case for each link, though, I simply do the following:
$(document).ready(function() {
// Get rid of “http://”
loc = location.href.substring(7);
// Get rid of domain name
loc = loc.substring(loc.indexOf(“/”));
// Get rid of fragment identifier
var i = loc.indexOf(“#”);
if (i > -1) loc = loc.substring(0, i);
// Highlight navigator links to this page
$(“#navigator a[href='" + loc + "']“).addClass(‘now’);
});
In other words, inspect each navigation link and select it if its target is the current URL.
Reply
February 22nd, 2010
Bobby JackBobby,
Very smart. I agree this is a better solution – especially if you’re dealing with more than a few pages.
Quick question: Why do you think a server-side solution is “far better”? I’m not disagreeing. Both methods have worked well for me in the past. It does, however, seem like a selected-state is behavior-related and would therefore be best handled with javascript. After all, we’re not making database call or anything. We’re just changing the style a bit.
Anyway, thanks for the snippet!
Reply
February 22nd, 2010
Cory SchiresOK, by “far better”, I guess I just meant “a bit better”
For one, this seems like a relatively important piece of functionality that should be available to all, not just those with javascript. Both our solutions are liable to fall over under certain conditions: ‘vanity’ URLs in both cases, specificity of the regexp pattern in your case; I’m sure there are one or two other edge cases.
Both our methods leave the link as a link, which isn’t ideal; with a server-side solution, it’s much more common to unlink the text altogether, which is better since it doesn’t leave an unnecessary self-referential link.
And, if you need a client-side solution, it’s usually better to add a unique id to the body tag of your page and target the relevant navigation that way, via straight CSS.
Reply
February 23rd, 2010
Bobby JackHey, is this supposed to work offline? ‘cos I can’t get it to work and I really don’t know what is the problem…
Reply
Antonio,
It will definitely work offline. Did you remember to include the jQuery library in your header before the script?
If you continue to have problems, send me your code and I’ll have a look.
March 5th, 2010 admin
March 5th, 2010
antonioAntonio,
It will definitely work offline. Did you remember to include the jQuery library in your header before the script?
If you continue to have problems, send me your code and I’ll have a look.
Reply
March 5th, 2010
Cory Schiresjq library is included before the script… here is css:
ul#menu li a.onama span {
background-position:0px -131px;
}
ul#menu li a.radovi span {
background-position:-100px -131px;
}
ul#menu li a.projekti span {
background-position:-200px -131px;
}
ul#menu li a.webdizajn span {
background-position:-300px -131px;
}
ul#menu li a.kontakt span {
background-position:-400px -131px;
}
this is my “over” state of the buttons, I did this with help of
http://www.shopdev.co.uk/blog/animated-menus-using-jquery/
this tutorial .
this is the script
$(document).ready(function() {
// store url for current page as global variable
current_page = document.location.href
// apply selected states depending on current page
if (current_page.match(/onama/)) {
$(“ul#menu li:eq(0)”).addClass(‘selected’);
} else if (current_page.match(/radovi/)) {
$(“ul#menu li:eq(1)”).addClass(‘selected’);
} else if (current_page.match(/projekti/)) {
$(“ul#menu li:eq(2)”).addClass(‘selected’);
} else if (current_page.match(/web_dizajn/)) {
$(“ul#menu li:eq(3)”).addClass(‘selected’);
} else if (current_page.match(/kontakt/)) {
$(“ul#menu li:eq(4)”).addClass(‘selected’);
} else { // don’t mark any nav links as selected
$(“ul#menu li”).removeClass(‘selected’);
};
});
and this is the html
thanks for trying to help.
Reply
March 5th, 2010
antonioYeah. WP doesn’t seem to like HTML in comments. I’ve been meaning to give people a better way to post
code snippits. At any rate…
Based on the link you posted, it looks like you’re trying to create a three-state menu using
background-image sprites. If so, you’ll probably need more css than what you’ve posted above.
At the very least, you’ll need to write some css for the “selected” class. Cause if
you don’t associate some style with the class, then it’s not going to do anything regardless if
jquery is properly applying the class.
It should look something like this:
/* selected class */
ul#menu li.selected a.radovi span {
/* insert sprite coordinates for your selected state bg */
background-position:-XXXpx -XXXpx;
}
Also, have a look at the list-item in firebug to see if the “selected” class is being at all.
Hope that helps.
Reply
March 5th, 2010
Cory Schires“Selected” class is applied according to firebug but it has no effect, roll-over is still functioning. I’m thinking that JavaScript solution is needed, that would freeze “span” opacity animation to 1…
Reply
March 6th, 2010
antoniowindow.onload = setActive;
function setActive() {
aObj = document.getElementById(‘footerTxt’).getElementsByTagName(‘a’);
for(i=0;i=0) {
aObj[i].className=’active’;
}
}
}
Try this, you don’t have to state every page!
Reply
April 20th, 2010
NameThank you so much fo this tip!
I’ve just spent half afternoon to solve this addClass with location.href!!!
I was trying with this code unsuccesfully:
$(document).ready(function() {
if (url=”http://www.blablabla.com/index.php/projects/gaming-design/?order=date”){
$(“a.sort1″).addClass(“selected”);
}
else if (url=”http://www.blablabla.com/index.php/projects/gaming-design/?order=alphabet”){
$(“a.sort1″).addClass(“none”);
}
})
Then i’ve implemented your one and now is working!!
Thanks!
Rics
Reply
February 9th, 2011
Rics