2

hey guys, what's the best way to do that:

i have a list

<ul>
    <li>hello</li>
    <li>good bye</li>
    <li>arrivederci</li>
    <li class="selected">dude</li>
    <li>whatever</li>
</ul>

Initially one item already has a class of .selected applied. When i hover over one of the list-items i want this one to have the .selected class. So every item should only have the class applied when im over, as soon as i leave the item the class get's removed and the next one has the class.

matt
  • 42,713
  • 103
  • 264
  • 397

3 Answers3

8

From your description, I think you want this:

$('ul > li').hover(function () {
    $(this).toggleClass('selected').siblings().removeClass('selected');
});

Demo: http://jsfiddle.net/swN5F/

Or, more likely what you want is actually:

$('ul > li').mouseenter(function () {
    $(this).addClass('selected').siblings().removeClass('selected');
});

Demo: http://jsfiddle.net/swN5F/1/ (note that the last-hovered item remains red)


Update: version that works with multiple <ul>s, and with up/down arrow keys:

var $activeUl = $('ul:first'); // For keyboard arrows

$('ul > li').mouseenter(function () {
    $(this).addClass('selected').siblings().removeClass('selected');
    $activeUl = $(this).parent();
});

$(document).keydown(function (e) {
    var direction, siblingsSelector;
    if (e.which == 38) { // up
        direction = 'prev';
        siblingsSelector = ':not(:first-child)';
    } else if (e.which == 40) { // down
        direction = 'next';
        siblingsSelector = ':not(:last-child)';
    }
    $activeUl.find('.selected')[direction]().addClass('selected')
        .siblings(siblingsSelector).removeClass('selected');
});

Demo: http://jsfiddle.net/zBjrS/36/

David Tang
  • 92,262
  • 30
  • 167
  • 149
  • thank you, but check out this: http://jsfiddle.net/zBjrS/33/ That's exactly what i want. when i use up and down arrows i can navigate through the items and if i hover as well. HOWEVER i have this case: http://jsfiddle.net/zBjrS/34/ and here you can see that it always remebers the last hover state for every ul. i want to work 34 exactly like 33! – matt Jan 16 '11 at 10:06
  • @user239831, see updated answer for modified version of your code. Hopefully this is what you want, though I had to assume that the last-hovered `
      ` is the one that the up/down arrows should target.
    – David Tang Jan 16 '11 at 10:29
  • thank you, but unfortunatley that is what i was able to already by myself. I don't want to have it working WITH multiple ul's but OVER multiple ul's. So it should actually look like there are no multiple ul's. :) i know that sounds weird but that's exactly my case. i have multiple ul's but the user shouldn't see that and so it should just work like there is one ul. exactly like it already is right here: jsfiddle.net/zBjrS/34 the UP and Down arrows work across all ul's without any problem. exactly the same should work with the hover. if i hover any li item the .selected class should be applied – matt Jan 16 '11 at 10:34
  • @user239831, sorry I misunderstood. Is it possible to combine all three `
      s` into one then? `$('li').appendTo('ul:first')`. This would be the simplest solution.
    – David Tang Jan 16 '11 at 10:38
3

Why don't you use built-in browser feature:

Markup:

<ul class="hoverUl">
    <li>hello</li>
    <li>good bye</li>
    <li>arrivederci</li>
    <li>dude</li>
    <li>whatever</li>
</ul>

CSS:

.hoverUl li { /* normal style */ }
.hoverUl li:hover { /* "selected" style */ }

This is a little bit different than what you asked because nothing will be selected at first, but why something should be selected if the selection is made by hover..

Preview

  • +1, pure speculation here, but the styling for the "default" selection should probably be different to the hover styling. – David Tang Jan 16 '11 at 09:53
  • @RC: because, while s/he's recreating the `:hover` pseudo-element I think (assume) the `selected` class is really meant to imply the location of the current page. – David Thomas Jan 16 '11 at 09:57
  • 1
    @RC: I think they want something to be selected even when the mouse isn't over it (e.g., they want the *last* item that had the mouse over it to be selected). Also `:hover` doesn't work on IE6 for non-anchor elements, and sadly IE6 remains a factor for some websites (hopefully in another year, though...). – T.J. Crowder Jan 16 '11 at 10:10
2

You can do that, using jQuery's hover:

$("selector_for_your_ul li").hover(
    function() {
        $(this).addClass("selected").siblings("li").removeClass("selected");
    },
    function() {
        $(this).removeClass("selected");
    }
);

Live example

That will switch the "selected" class to the li that the mouse is over, and if the mouse leaves one li and doesn't enter another, it will remove the class (no none of them will have the "selected" class). I think that's what you said you wanted, although it doesn't match up with having one of them already have the "selected" class at the outset.

If you just want to change it when someone mouses over an li but not remove it when the mouse leaves an li without entering another, use mouseenter:

$("selector_for_your_ul li").mouseenter(
    function() {
        $(this).addClass("selected").siblings("li").removeClass("selected");
    }
);

Live example

If you look up the mouseenter event in various references, they'll tell you it's IE-specific. That's true, but it's so useful that jQuery emulates it on other browsers.

Update: You can change the siblings("li") to siblings("li.selected") in the above if you like, e.g.:

$(this).addClass("selected").siblings("li.selected").removeClass("selected");

That may make it slightly more efficient (not trying to remove a class from something that already has it). Here's the first example (with hover) updated to do that; here's the second example (with mouseenter) updated to do that.


Off-topic: But depending on which effect you want, you may be able to achieve it with CSS rather than with jQuery and a "selected" class. If you just want the li highlighted when the mouse is actually over it (the hover example above), rather than leaving the last li highlighted (the mouseenter example above), and if you don't need to support IE6, you can do it using the CSS :hover pseudoclass:

selector_for_your_ul li:hover {
    color: red; /* ...or whatever... */
}

Live example But again, that's only if you want the hover effect, and only if you don't need to support IE6 (which only allows :hover on a elements).

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Have you accounted for the fact that there is an initially-selected item? It might just be *really* early, but I expected that the `mouseover` portion requires a `$('li.selected).removeClass('selected');` statement... – David Thomas Jan 16 '11 at 09:47
  • @David: Yes, the above works fine with an initially-selected item. (Just added live examples showing that.) That's what the `.siblings().removeClass("selected")` is for. Having added the class to the item the mouse has entered, we find the sibling `li` elements of that element and remove "selected" from them. – T.J. Crowder Jan 16 '11 at 09:49
  • Ahhh...of course, it's just early... *cough* yawn *cough* =/ +1 – David Thomas Jan 16 '11 at 09:55