Focus on This

by Javier Varela on Mar 5, 2019

Focus is, in short, “the control mechanism in the screen that receives input from the keyboard”. Almost every user is adept at managing their focus on forms; tabbing through form elements to enter information in different text fields, for instance.

There are users that exclusively use the keyboard to navigate web applications. Others rely on focus to ensure a slick and smooth experience when navigating within an app, as they cannot use the mouse alternatively.

Therefore, according to the webaim.org accessibility standards, “all page functionality should be available using the keyboard, unless the functionality cannot be accomplished in any known way using a keyboard”.

Focus helps us to reach on-screen content via the keyboard, but what should be ‘focusable’? All content? The rule of thumb is that all interactive elements on the page should include , as mentioned before, form elements such as text fields, select lists, radio buttons, and hyperlinks. These elements are included automatically into the tab order of the page, which should prove logical enough for the user, alongside built-in keyboard event handling.

Other things, such as ordering table headers using the keyboard, or when interacting with table rows, need to be included in tab order because they do not receive focus by default, using tabindex html attribute…

tabindex=“-1” means that the element will not be in the tab order,

tabindex=“0” will add the element to the natural tab order of the page.

We tend not to use other integer values on tabindex as it is considered a sort of antipattern…

Nor it is normal to use tabindex on important elements on the page that are not interactive, such as headings, due to them not being interactive controls, and screen reader users have other ways to explore non-interactive elements on the page, so there’s no need to tab through them.

In this post, we want to talk about some techniques that will improve the experience for users who rely heavily on the keyboard when focusing through a page. The first one is one we learnt from Chrome Developer Relations Team member Rob Donson, and it’s called “Managing focus”

If we think of our own PFM/BFM application, we have a nav bar in the top of our dashboard that allows the user to navigate through different sections in our app.

<nav>
  <a href="/transactions">Transactions</a>
  <a href="/invoicing">Invoicing</a>
  <a href="/financial-calendar">Financial Calendar</a>
  <a href="/scheduled-transactions">Scheduled Transactions</a>
</nav>

 

If the user selects one of them, the application doesn’t refresh the whole page, obviously, but specific areas of DOM will change to show new fetched data for that standalone widget. For instance, if we are displaying a financial analysis widget, and we want to switch to a financial calendar, it would probably be tedious to tab through all the menu options before reaching the main area content we have selected.

In this case what we do is programmatically focus on the heading of the new loaded content after clicking the nav bar option. To do this, we need to give a tabindex value of -1 to that heading, and call focus() method to actually focus on the aforementioned heading. This way, the screen reader announces to the user that new content is reached, and the user can continue navigating from this heading over the widget.

<main>
  <h2 tabindex="-1">Financial Calendar</h2>
</main>
<script>
  function onNewPage() {
    var heading = document.querySelector('h2');
    heading.focus();
  }
</script>
 
 

As we mentioned, navigating through all the options of the menu every time we want to choose one of them can be frustrating and tiring for screen reader users. Another technique that we learnt to help with this is called “Skip navigation links”, which is basically a hidden link at the beginning of the page before all navigations, sublists, sidebars, and menus, which are often at the beginning of the DOM. Hidden to the eye of the user, but not for the focus tab order, this link allows the user to jump straight to the main content of the area when selected, without jumping the hurdles of all the nav content at the beginning. Basically, It’s a shortcut straight to the point.

<body>
<a href="#maincontent">Skip to main content</a> 
...
<main id="maincontent">
<h1>Heading</h1>
<p>This is the first paragraph</p>

Sometimes in our applications, we have to build complex components that we need to customise. As developers, we use components that usually come from libraries, or we create them from scratch. It’s important to remember when designing the functionality of these components that we need to match standards when it comes to determining keyboard interaction. The best way to do this, in terms of getting a good accessibility reference, is to check ARIA Design Patterns. For instance, when creating a radio button component, we must make sure that by pressing down the arrow key the user will be able to move focus to the next radio button, and once having reached the last in a sequence, focus will then return to the first item. We can do this using a technique known as roving tabindex for managing focus within the radio groups:

<div role="radiogroup"
     aria-labelledby="group_label_1"
     id="rg1">
  <h3 id="group_label_1">
    Pizza Crust
  </h3>
  <div role="radio"
       aria-checked="false"
       tabindex="0">
    Regular crust
  </div>
  <div role="radio"
       aria-checked="false"
       tabindex="-1">
    Deep dish
  </div>
  <div role="radio"
       aria-checked="false"
       tabindex="-1">
    Thin crust
  </div>
</div>
<div role="radiogroup"
     aria-labelledby="group_label_2"
     id="rg2">
  <h3 id="group_label_2">
    Pizza Delivery
  </h3>
  <div role="radio"
       aria-checked="false"
       tabindex="0">
    Pickup
  </div>
  <div role="radio"
       aria-checked="false"
       tabindex="-1">
    Home Delivery
  </div>
  <div role="radio"
       aria-checked="false"
       tabindex="-1">
    Dine in
  </div>
</div>
<script type="text/javascript">
  var rg1 = new RadioGroup(document.getElementById('rg1'));
  rg1.init();
  var rg2 = new RadioGroup(document.getElementById('rg2'));
  rg2.init();
</script>

The last thing we are going to cover in this article related to focus is focus trapping. Simply put, we can say that “when we are in a dialog and we press tab, focus should only cycle amongst interactive elements inside the dialog”. Therefore, just as we need to return to the first item from the last within a radio group, in a dialog we need to implement a technique that has the same effect, in order to trap the focus within the dialog context. According to thisdetailed article from MDN about dialog role and how its focus should behave, this makes total sense, because we don’t want to get out of the context in a dialog until we’ve finished any interaction within it.

In the same way, when we close a dialog, ideally we want to go straight back to whatever element we accessed the dialog from. A perfect example from our PFM / BFM application could be when we are in a transaction, and we want to edit it, we can tab through all the rows, and just by pressing enter we can shift to a panel that allows us to edit that particular transaction. When we submit changes, the user should then go straight back to the transaction prior to entering the edit panel.

This is the screen when we are in a panel, and as you can see, the shadow doesn’t allow you to click outside the panel, but before applying focus trap technique you could tab out from it, which is not ideal for a user that only uses keyboard.

 

To avoid this tab scape from dialog, we try to think in a way that is consistent with native browser behaviour. I found some good references about it by diving into Stackoverflow. In a nutshell, we need to move all elements from body into div with tabIndex=-1, get our dialog out of that div and give a positive tabIndex, and set aria-hidden to the Div, to not let the screen reader read anything outside the dialog. This is especially useful to not allow screen readers that don’t necessarily use tab to exit the dialog.

Since we use React in our application, we did a bit of research to find something that could match our expectations, and we came across this react-focus-lock component, which has the principal advantage of not emulating keyboard control, but mainly watching focus behaviour. Quoting its creator, component remembers the last focused item, and on focusOut:

  1. finds common parents of modal and document.activeElement
  2. gets all tabbable elements inside common parent.
  3. gets all tabbable elements inside the Modal
  4. Finds the difference between last focused item and current.
  5. If diff(current-active)>1 -> returns focus to the last node.
  6. If current < first node -> goes to the last-by-order
  7. If current > last node -> goes to the first-by-order
  8. If first < current < last -> moves cursor to the nearest-in-direction

For using it, just wrap something with focus lock:

import FocusLock from 'react-focus-lock';

 const JailForAFocus = ({onClose}) => (
    <FocusLock>
      You can not leave this form
      <button onClick={onClick} />
    </FocusLock>
 );

Sounds like we have some work to do in our web app to properly handle focus! I encourage you to try it in your application and see how it works in terms of focus handling… Just think, it’s a small price to pay to make your application that much more accessible.


 The original version of this post can be found on Strands Tech Corner on Medium 

 The original version of this post can be found on Strands Tech Corner on Medium 

Get the latest updates here

SUBSCRIBE HERE