Improving Usability, Accessibility and ARIA Compliance with Grid Keyboard Navigation

Zdravko Kolev
Ignite UI
Published in
8 min readJun 3, 2020
Photo by Julien Pouplard on Unsplash

As user expectations evolve, modern web applications have grown more and more complex. They define user interface patterns like virtualized scrolling of content, complex data tables with editable cells, and different overlay components, just to name a few. That is not a problem for users leveraging a mouse or touchpad, as they can easily navigate through the page elements and interact with them. But for those using a keyboard, this can dramatically impact their user experience. The number of controls and items on most web pages has increased dramatically — meaning that a modern web page may contain hundreds of tab stops.

At Infragistics, we want to ensure optimal user experience, regardless of whether you are using a mouse, a touchpad, or just a keyboard. That is why we have created a new user interface pattern for keyboard navigation within a page, called Active element navigation. This pattern reduces the number of tab stops within the interface designed for the Ignite UI for Angular Data Grid to only five and exposes plenty of new keyboard shortcuts for efficiency. Each tab stop element has a single-entry point, and from there, users can easily navigate to different items in the corresponding grid element container by simply using the arrow keys. Thus, simplifying navigation and improving usability.

Page tab sequence

As described in the Fundamental Keyboard Navigation Conventions section of W3C’s WAI-ARIA Authoring Practices 1.1, the tab sequence should include only one focusable element of a Composite UI Component — and we have five such Composite UI Components, hence five tab stops:

  • Toolbar/Group by Area, if existing
  • Header row container — The first cell of the header row will become active
  • Tbody — The first igxCell (0,0) of the body container will become active
  • Footer — The first cell in the Column Summary will become active (if summaries are enabled)
  • Pager UI — Items per page drop-down will become active

Pressing the Tab key will move the focus out of the current container to the next element in the tab sequence — This is illustrated with the image below with the tab sequence “Grid Toolbar” -> “Grid Headers” -> “Grid Body Container” -> “Summaries” -> “Footer — Grid Paginator”.

Each of the five tab-stop containers can be considered as a separate grouping entity, reducing the number of tab stops on the page. The Grid has a rich DOM structure, along with plenty of virtualized containers, which allows for greater performance. Therefore, we have more than one focusable Grid element part of the page tab sequence and allows us to have separate and rich navigation on all tab stop containers.

Note: Keep in mind that the default-browser-focusable actions are persisted. We are not preventing the focus of the HTML element part of ng-templates or other elements added separately in the Grid. The browser will handle its focus actions by default — there is no need to apply additional focusable directives.

Active Element Navigation

Referring back to W3c’s Fundamental Keyboard Navigation Conventions, all interactive UI components need to be accessible via a keyboard. This is best achieved by either including them in the tab sequence or by making them reachable from a component that is in the tab sequence. In the Grid’s case navigation, it is possible to move through each one of these focusable containers with the navigation keys (Arrow keys, home/end, ctrl + ‘action key’) and this is where the Active element navigation concept kicks in. Active element is the first visible element from the focused container. BUT this element does not become focused — the focus remains on the actual container. The active element gives you the ability to navigate through most of the Grid elements, and activate features based on the focused Composite component.

How Do Focused Elements Differ with Selected and Active Elements?

We consider the focused element as a pointer — it tracks the path of navigation (page tab sequence). As we already know, we have five such composite elements. The `Active element` is used to navigate through these focusable containers. As you can see in the image below, for visual users, the thick orange border with the gray cell background indicates the currently active element.

Selected elements are elements that have aria-selected=”true”. In the igxGrid case, aria-selected is applicable to all three types of selection elements — cell, row and column selection (WAI-ARIA)

In conclusion

  • Focused element — tracking the path of page tab sequence — Grid’s toolbar, header, body, footer, and pager
  • Active element — navigates within the five focusable containers with the arrow keys (and special keys like home/end )
  • Selected element — having aria-selected=”true” along with Grid selection styles applied (cell, row or column selection )

We follow the guidelines within the WAI-ARIA Authoring Practices Guide, for specific recommendations on key and behavior mapping. So, the roles that ARIA Grid provides are recognizable in the igxGrid as well: grid, row, grid cell, row header, and column header.

Tab navigation

The grid follows the primary keyboard navigation convention that the and tab keys move the focus from one UI component to another. The arrow keys change the active state inside of components that include multiple elements. shift + tab

Compared to previous tab interaction behavior, we’ve changed the following:

  • You cannot use tab key to navigate between the cells in the IgxGrid. The navigation is now performed only with arrow keys.
  • With the to tab key you can only navigate to the next editable cell (Only when the cell is in edit mode). When the last editable cell (of the row) is reached, the navigation will continue to next row’s editable cell. If the last editable cell is reached, the tab navigation will continue the next focusable tab stop element.

Performance improvements and code enhancements

As a result of the new keyboard navigation concept, we have been able to optimize our code and implement performance improvements, such as:

  • Wheel and view detach handlers have been removed as well.
  • Reduced navigation services. We previously had four navigation services for the Grid, Hierarchical Grid, Tree Grid, and MRL functionality. Now we have only three. With the old implementation, on scrolling with virtualized content, we were changing the cell context (the actual shell remained the same) and had a problem with the browser not allow ing us to focus on an already focused element — we have had to blur the cell focus, change the cell context and focus it again. Now that is no longer an issue.
  • Touch device enhancements — now if we have a focused cell on scrolling, we blur the cell before detaching the wheel handler.
  • Application-level performance boost with `events stacking`. Use ` ngZoneEventColescing : true`

Const bootstrap = () => platformBrowserDynamic().bootstrapModule(AppModule, { ngZoneEventCoalescing: true });

Keyboard Navigation Feature Integration

Now let’s focus on the keyboard navigation features integration. Our grid has plenty of features and we’ve considered all of them carefully to ensure that they work properly with the new changes.

Ctrl + Shift + L will open the Excel-style filter/default (row) filter

Alt + L opens the advanced filter dialog

Ctrl + Arrow up sorts the active column header in ASC order. If the column is already sorted in ASC, it will remove the sorting (tri-state none)

Ctrl + Arrow down sorts the active column header in DSC order. If the column is already sorted in DSC, it will remove the sorting (tri-state none)

Shift + Alt + Arrow right to group by the active column.

Shift + Alt + Arrow left ungroup the active column (remove it from the group by criteria)

Alt + left/up arrow key — collapse

Alt + right/down arrow key — expand

Note: If you are using a screen-reader, keep in mind that on initial header click, we are focusing the whole header container and the screen reader will read all header captions. Following a click on the header , the header caption + selection state will be read. Example — Company name, column header selected.

  • Cell editing — now the tab navigation works only for editable cells (In edit mode). On cell editing with Tab navigation, if we reach the end of the grid, the last cell will be submitted , and the navigation will continue to the next available tab stop element.
  • Filtering (filtering chips) — Tab navigation for chips is removed, navigation is possible only by using arrow keys. Also:

Chips are part of the column header now. Chips are not focusable elements anymore

  • Paging — richer accessibility. Added tooltips, aria- labels, and roles.
  • Default Key combination updates:

Ctrl + any other key works only on real cells, not on a grouped row area. This is a difference compared with the old behavior. GroupBy and Master-Detail don’t work with Ctrl+ arrow keys.

Ctrl + Right/Left Arrow works only on the common cells, summary row, and headers

Home and End (and Ctrl Home/End) works as expected, there are no changes here.

We now provide richer visual styling for the tab stops/header element/body cells/summaries/paging/group by/master-detail/MRL/cell editing

Thanks to the combined efforts of our developers we’ve managed to significantly reduce keyboard navigation complexity. The overall keyboard interaction is now improved, intuitive to use, offering better usability, while ensuring accessibility. We understand the need for continuous innovation and that great features are a result of true collaboration

Don’t forget to check out the rest of the new features and enhancements that were released as part of our Ignite for Angular 9.1.0 release. Please share any comments or questions in the Comment s section below.

Originally published at https://www.infragistics.com on June 3, 2020.

--

--

Zdravko Kolev
Ignite UI

Product Development Manager at Infragistics, passionate about technology, innovation, personal growth, leadership, and team development.