Div with overflow auto is not tab-focusable in Chrome

Viewed 664

I have two divs with a max-height and overflow auto. One div does not overflow and the other does. Scrollable divs can be scrolled with the keyboard, but the behavior is different between Firefox and Chrome:

  • Firefox: The scrollable div is tab focusable even though I have not specified a tab index on it. The unscrollable div cannot be focused. This is a nice default behavior which I want.
  • Chrome: The scrollable div cannot be tab focused unless I add tabindex="0" to force it. In my use case the content of each div is user-generated and I do not know if it will overflow or not, so I can't just apply tabindex="0" to all divs because it will make the unscrollable divs focusable which I do not want.

Note that Chrome allows the scrollable div to be scrolled if you click the div first then press arrow up/down, but this doesn't actually focus the div (the div does not become the document.activeElement). It seems Chrome remembers which element was last clicked. This is not a keyboard-only solution which I am looking for.

Basically I would like Chrome to work like Firefox in this scenario. Is this even possible? Maybe there's an accessibility setting in Chrome which enables this (I couldn't find one). How would keyboard-only users deal with this situation in Chrome?

div {
  overflow: auto;
  max-height: 50px;
  border: 1px solid black;
  margin: 10px 0;
}

div:focus {
  outline: 2px solid blue;
}
<div>
  Text does not overflow, not scrollable and should not receive tab focus.
</div>

<div>
  Text overflows and should be tab focusable so that it can be scrolled with the keyboard.<br>
  Text overflows and should be tab focusable so that it can be scrolled with the keyboard.<br>
  Text overflows and should be tab focusable so that it can be scrolled with the keyboard.<br>
  Text overflows and should be tab focusable so that it can be scrolled with the keyboard.
</div>

1 Answers

Assuming these are keyboard only users and not screen reader users (as they would use different controls) the easiest way to do this is with a little bit of JavaScript and add tabindex="0" if an element has scrollbars (both vertical and horizontal).

Working out if an element has vertical or horizontal scrollbars can be achieved with one line of JavaScript

if(el.scrollWidth > el.clientWidth || el.scrollHeight > el.clientHeight){//scrollable}

I have included an example below where I set the tabindex="0" on a container if it has scrollbars.

If the contents of these divs may change you will probably want to use a mutation observer to listen for the changes.

I have included this in the example below as well for you.

var els = document.querySelectorAll('.isItScrollable');

//observer setup
var observer = new MutationObserver(mutatedDiv);
var objConfig = {
            childList: true,
            subtree : true,
            attributes: false, 
            characterData : false
          };

//see if the scroll width or height is larger than the client width or height
function isScrollable(el){
   if(el.scrollWidth > el.clientWidth || el.scrollHeight > el.clientHeight){
       return true;
   }
   return false;
}


for(var x = 0; x < els.length; x++){
  var el = els[x];
  //check whether the element is scrollable initially.
  if(isScrollable(el)){
    el.setAttribute('tabindex', 0);
  }
  //use an observer to check for a change so we can check if the content updates
  observer.observe(el, objConfig);
}

//observer callback function
function mutatedDiv (mutations) {
  mutations.forEach(function(mutation) {
    if(isScrollable(mutation.target)){
      mutation.target.setAttribute('tabindex', 0);
    }else{
      mutation.target.removeAttribute('tabindex');
    }
  });
}


////////////not relevant, just for demo
var add1 = document.querySelector('.addone');

add1.addEventListener("click", function(e){
    els[0].innerHTML = "Text overflows and should be tab focusable so that it can be scrolled with the keyboard.<br>Text overflows and should be tab focusable so that it can be scrolled with the keyboard.<br> Text overflows and should be tab focusable so that it can be scrolled with the keyboard.<br> Text overflows and should be tab focusable so that it can be scrolled with the keyboard.";
});

var remove1 = document.querySelector('.removeone');

remove1.addEventListener("click", function(e){
    els[0].innerHTML = "Text does not overflow, not scrollable and should not receive tab focus."
});

var add2 = document.querySelector('.addtwo');

add2.addEventListener("click", function(e){
    els[1].innerHTML = "Text overflows and should be tab focusable so that it can be scrolled with the keyboard.<br>Text overflows and should be tab focusable so that it can be scrolled with the keyboard.<br> Text overflows and should be tab focusable so that it can be scrolled with the keyboard.<br> Text overflows and should be tab focusable so that it can be scrolled with the keyboard.";
});

var remove2 = document.querySelector('.removetwo');

remove2.addEventListener("click", function(e){
    els[1].innerHTML = "Text does not overflow, not scrollable and should not receive tab focus."
});





    
.isItScrollable {
  overflow: auto;
  max-height: 50px;
  border: 1px solid black;
  margin: 10px 0;
}

.isItScrollable:focus {
  outline: 2px solid blue;
}
<div class="isItScrollable">
  Text does not overflow, not scrollable and should not receive tab focus.
</div>

<div class="isItScrollable">
  Text overflows and should be tab focusable so that it can be scrolled with the keyboard.<br>
  Text overflows and should be tab focusable so that it can be scrolled with the keyboard.<br>
  Text overflows and should be tab focusable so that it can be scrolled with the keyboard.<br>
  Text overflows and should be tab focusable so that it can be scrolled with the keyboard.
</div>

<button class="addone">Add Text Div One</button>
<button class="removeone">Reset Text Div One</button>
<button class="addtwo">Add Text Div Two</button>
<button class="removetwo">Remove Text Div Two</button>

Related