Search code examples
javascripthoveronkeydown

How do I simulate hover with Javascript on keydown?


First of, I'd like to use only native JavaScript to complete this task.

Let's say I am to make a custom dropdown, and the HTML code looks kind of like this.

<div class="dropdown">
  <span class="dropdown-label" style="display:block">Select a thing</span>
  <ul class="dropdownItemContainer">
    <li>Item 1</li>
    <li>Item 2</li>
    <li>Item 3</li>
    <li>Item 4</li>
    <li>Item 5</li>
    <li>Item 6</li>
  </ul>
</div>

In the CSS file I have something close to this:

ul.dropdownItemContainer li:hover {
  background-color: #FF0000;
}

Yeah, there's really no dropdownish behavior, but it's not the point of discussion actually. The problem is that I couldn't think of a decent way to enable keyboard control for this dropdown. The desired outcome is the following: I press the down key, and the first option is highlighted; I press it again, and the second option is highlighted and so on.

The only option that I see at this point (just started studying JS) is to fetch all of the ul's children, stick'em into an array and assign the tags a background color through JS methods in a proper way whenever the down key is pressed.

On the other hand, I still have the :hover behavior described in the CSS for mouse countrol. Is there a smart way of simulating hovers?


Solution

  • I would go with a simple assignment of a class on your li-elements and steer it with a keydown handler. The following code is not meant to be complete but give you something you can work with.

    var active = document.querySelector(".hover") || document.querySelector(".dropdownItemContainer li");
    
    document.addEventListener("keydown",handler);
    document.addEventListener("mouseover",handler);
    
    function handler(e){
        console.log(e.which);
            active.classList.remove("hover");
        if (e.which == 40){
            active = active.nextElementSibling || active;
        }else if (e.which == 38){      
            active = active.previousElementSibling || active;
        }else{
            active = e.target;
        }
            active.classList.add("hover");
    }
    

    You can see a working example here