Keyboard Accessibility in JavaScript: Interactive Elements, Focus and Navigation

Keyboard Accessibility in JavaScript

Keyboard accessibility is a crucial aspect of web accessibility. A lot of internet users surf the web and navigate web pages using only their keyboard. This is done either for convenience, personal preference or due to a motor disability; making sure that your website is keyboard navigable benefits a wide range of users.

There are multiple ways you can optimize your websites for accessibility, one simple way is by implementing event listeners using JavaScript. This provides a number of ways to present, update, and enhance content on a web page on the fly without having the user refresh the page, which is especially useful to users using assistive technology.

Interactive Elements

Assistive technologies rely on interactive elements(i.e forms, buttons) to understand and interact with elements on a web page.

Which implies that any discrepancy in how interactive elements are presented can negatively affect users and assistive technologies such as screen readers and speech-input software. 

Incorrect element properties can also cause issues with assistive technologies because they use attributes such as Name, Role and Value of UI elements to parse controls and structure properly. This is also part of the WCAG criterion WCAG 4.1.2 Name, Role, Value.

Focus Management

Most of the time you don’t need custom focus management for simple native HTML elements such as , the <button> tag for buttons, the <input> tag for user input and the anchor <a> tag for links. Native HTML elements are accessible out-of-the-box and have predefined roles and global tab index attributes of “0”. This allows the elements to be focusable with the tab key and establish a sequential focus order. 

The only time focus order can be an issue is when you’re building custom components or designs that require manual focus management. In this case, focus order can end up being inconsistent with the design and sequential logic of the content on the website. An example of such a design pattern is the use of modal popup dialogs, when activated require the focus to be trapped inside the overlay and not move to the elements in the background. 

Tabindex

In some cases, you might want to apply focus to an element that is not focusable by default. You can do that by using the tabindex attribute which makes unfocusable elements focusable. Remember that you shouldn’t be using tabindex on elements that don’t need it such as buttons.

There are three methods you can use with tabindex:

  • tabindex= ”0” allows custom elements other native HTML elements  to receive keyboard focus.<div> and < span > are examples of such elements that may require a tabindex=”0”. It works by placing the element in the logical navigation flow and doesn’t change the tab order.
  • tabindex= “-1” will remove the element from the navigation order, meaning that you won’t be able to access it via <TAB>, but can be focusable using JavaScript. This is useful when creating accessible interactive widgets in JavaScript. Take the example of the modal again. The button that activates the modal should have tabindex=”0” but the modal itself will have a tabindex=”-1” to remove it from the tab order and prevent a user from tabbing through the contents of the modal that isn’t active yet.
  • tabindex= ”1” and above will be the first elements to be focused starting from one. This would be useful if you wanted a focusable element removed from the tab sequence. Keep in mind that using a positive integer when using tabindex is not advisable and bad practice for accessibility. This can break the expected tab order and create a confusing user experience when tabbing across interactive elements on your website, especially if content is dynamically added to the website.

Tab Order

Users who are unable to navigate the web using a mouse or a trackpad, will often rely on the tab key. Making it one of the most important keys on a keyboard for users with motor disabilities. The Tab key is often used to navigate through focusable elements like forms and buttons on a web page. 

The HTML DOM which regroups all the properties, methods and events of HTML elements on a web page can end up having a broken tab order if focusable elements aren’t in a correct order relative to how a website is designed.

Because the Tab key will jump to Interactive elements in the order they appear in the DOM, not how they appear visually. You can easily solve that by having your source code match the visual hierarchy of your website front-end design. 

The default Tab order should be logical, intuitive and follow the visual flow of the web page. Similar to a book, it should be going from left to right, top to bottom.

Focus Styling

How focus is styled is as important as focus order, it doesn’t matter how good focus is managed if the user doesn’t know which button or link is currently being selected as he tabs through the page. 

Modern web browsers have different visual stylings for how focusable elements are selected, some more visible than others. To avoid having issues with styling, within your stylesheet you should avoid setting the focus outline to none or 0, because this will override the browser’s default focus indicator if you’re using a custom theme.

How To Improve Accessibility Using JavaScript?

We can improve accessibility using HTML and CSS, they can do the job most of the time. But when dealing with more complex designs and components then JavaScript is the solution.

JavaScript, unlike HTML and CSS, can trigger events based on the user’s actions.

Let’s have a look at some useful methods we can use in JavaScript:

Focus()

This method allows us to bring the keyboard focus to an element that’s either tabbable or focusable. This is a quite useful method for keyboard accessibility.

Here’s an example where focus is set to the input as soon as the page loads:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Focus Example</title>
</head>
<body>
    // Input field
  <input type="text" id="myInput" placeholder="Type here">

  <script>
    // Focus on input when page loads
    document.getElementById('myInput').focus();
  </script>

</body>
</html>

Here when the page loads the .focus() selector is used to focus on the input field called myInput.

OnKeyDown()

The OnKeyDown() method will listen to whether a key was pressed or not, in this case we will be enabling a user to click a button with either the <space> or <enter> key.

A common practice we see in today’s web development practices is to style a link to look like a button.

I am a power keyboard user and expect that if I come across a button, it will be activated with either the Enter or Space key. If it is actually a link made to look like a button and I use my Space key to activate it, there is a page scroll. This raises important accessibility issues when a user expects a known interaction to take place and the opposite happens. This can be fixed by adding a keydown event to the link to allow it to be fired with the Space key. 

Let’s have a look at an example:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Keydown Example</title>
</head>
<body>

  <button id="MyButton" onclick="PerformAction()" onkeydown="HandleKeyDown()">
    Click me, press space or enter!
  </button>

  <script>
    function PerformAction() {
      alert('Button clicked!');
    }

    function HandleKeyDown(event) {
      // Check if pressed key is Enter (key code 13) or Space (key code 32)
      if (event.key === 'Enter' || event.key === ' ' || event.keyCode === 13 || event.keyCode === 32) {
        PerformAction();
      }
    }
  </script>

</body>
</html>

When the button is brought into focus and the <space> or <enter> key are pressed the HandleKeyDown() function is called through the OnKeyDown() method.

The HandleKeyDown() method will check if the <enter> or <space> key were pressed using their key code which are 13 and 32 respectively.

It then calls the PerformAction() function which triggers an alert box.

SetAttribute()

This method is used to set attributes to elements, while not directly related to focus and accessibility it can be used to enhance user experience, such as dynamically changing attribute values of elements relative to their change in states. 

Let’s have a look at an example where the SetAttribute() method is used to toggle the aria-expanded attribute of a dropdown menu:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Dropdown Menu with aria-expanded</title>
  <style>
    .dropdown {
      position: relative;
      display: inline-block;
    }

    .dropdown-content {
      display: none;
      position: absolute;
      background-color: #f9f9f9;
      box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
      padding: 8px;
      z-index: 1;
    }

    .dropdown:hover .dropdown-content {
      display: block;
    }
  </style>
</head>
<body>

  <div class="dropdown">
    <button id="dropdownButton" aria-expanded="false" onclick="toggleDropdown()">
      Toggle Dropdown
    </button>
    <div class="dropdown-content" aria-labelledby="dropdownButton">
      <a href="#">Option 1</a>
      <a href="#">Option 2</a>
      <a href="#">Option 3</a>
    </div>
  </div>

  <script>
    function toggleDropdown() {
      var dropdownContent = document.querySelector('.dropdown-content');
      var dropdownButton = document.getElementById('dropdownButton');

      // Toggle visibility of the dropdown content
      if (dropdownContent.style.display === 'none' || dropdownContent.style.display === '') {
        dropdownContent.style.display = 'block';
        dropdownButton.setAttribute('aria-expanded', 'true');
      } else {
        dropdownContent.style.display = 'none';
        dropdownButton.setAttribute('aria-expanded', 'false');
      }
    }
  </script>

</body>
</html>

The toggle button’s aria-expanded attribute is set to false by default when the menu is collapsed. When it’s clicked the toggleDropdown() function is called using the OnClick() method.

The toggleDropDown() function expands the dropdown and changes the value of aria-expanded to ‘true’.

When it’s clicked a second time, the drop-down collapses and the aria-expanded attribute is set to ‘false’.

Conclusion

Keyboard accessibility is still an issue today as websites become increasingly complex in terms of features and designs which are often not optimized for keyboard accessibility, navigation and focus management.

And this requires us to devise ways to solve those accessibility issues using JavaScript’s event handlers and various other techniques. Allowing us to detect a user’s actions on a web page and perform certain modifications enhancing focus, navigation and accessibility.

Leave a Reply

Your email address will not be published. Required fields are marked *

Categories

Save Time with Dashboards – An Innovative Approach to Measure Accessibility KPIs


“What’s measured, improves”

Related Articles

Need help? Book a call at a time to suit you

Schedule a 30 minute free appointment to talk to one of our experts. We will take this time to understand what you want to achieve before we go into business.
Skip to content