Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scrolling inner div on key down and up

I have build an autocomplete container which displays the first four results and the rest are hidden and can be seen when scrolling the inner div element which holds all the results.

I have implemented the on key up when pressing the up and down keys in order to let the users navigate easily through the results but the inner div with the results isn't scrolling.

How can you scroll an element which has overflow-y:hidden and not the window ?

jsFiddle example here

In the example , just press any key inside the input box and use your arrows to go down, you will see that the div isn't scrolling

like image 568
Alon Avatar asked Apr 24 '14 11:04

Alon


2 Answers

By using tabIndex="-1" attribute on each of the children of a container, the browser will automatically scroll the container to have the child with the current focus in-view.

Demo (vanilla javascript):

var listElm = document.querySelector('ul')

// Mark first list item
listElm.firstElementChild.focus()

// Event listener
window.addEventListener('keydown', onKeyDown)

// Event callback
function onKeyDown(e){
  e.preventDefault()
  
  var selectedElm = document.activeElement,
      goToStart,
      // map actions to event's key
      action = {ArrowUp:"previous", Up:"previous", ArrowDown:"next", Down:"next"}

  selectedElm = selectedElm[action[e.key] + "ElementSibling"];

  // loop if top/bottom edges reached or "home"/"end" keys clicked
  if( !selectedElm || e.key == 'Home' || e.key == 'End' ){
    goToStart = action[e.key] == "next" || e.key == 'Home'
    selectedElm = listElm.children[goToStart ? 0 : listElm.children.length - 1]
  }
  
  selectedElm.focus()
}
ul{ 
  list-style: none; 
  border    : 1px solid silver; 
  max-height: 170px;
  padding   : 0;
  margin    : 0;
  scroll-behavior: smooth; /* nice smooth movement */
  overflow  : hidden;      /* set to hidden by OP's request */
}

li{ padding:.5em; margin:0; }
li:focus{ background:LIGHTSALMON; outline:none; }
<ul>
  <li tabIndex="-1">item 1</li>
  <li tabIndex="-1">item 2</li>
  <li tabIndex="-1">item 3</li>
  <li tabIndex="-1">item 4</li>
  <li tabIndex="-1">item 5</li>
  <li tabIndex="-1">item 6</li>
  <li tabIndex="-1">item 7</li>
  <li tabIndex="-1">item 8</li>
  <li tabIndex="-1">item 9</li>
  <li tabIndex="-1">item 10</li>
  <li tabIndex="-1">item 11</li>
  <li tabIndex="-1">item 12</li>
  <li tabIndex="-1">item 13</li>
  <li tabIndex="-1">item 14</li>
  <li tabIndex="-1">item 15</li>
</ul>

To make this list accessible (ARIA) read this

like image 81
vsync Avatar answered Sep 22 '22 17:09

vsync


You can update your script to find the relative position of the selected element and scroll to it:

$(".someInput").on("keyup", function(e) {
   $(".wrapper").show(); 
    if (e.which == 40) {
        $('.element:not(:last-child).element-hover').removeClass('element-hover').next().addClass('element-hover');
    } else if (e.which == 38) {
        $('.element:not(:first-child).element-hover').removeClass('element-hover').prev().addClass('element-hover');    
    }
    //scroll to element:
    $(".wrapper .inner_div").scrollTop(0);//set to top
    $(".wrapper .inner_div").scrollTop($('.element-hover:first').offset().top-$(".wrapper .inner_div").height());//then set equal to the position of the selected element minus the height of scrolling div
});

http://jsfiddle.net/kMzR9/3/

like image 39
Moob Avatar answered Sep 22 '22 17:09

Moob