Log in to like this post! Improving Usability, Accessibility & ARIA Compliance with Grid Keyboard Navigation Zdravko Kolev / Tuesday, June 2, 2020 (Last updated: April 13, 2023) 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 significantly, meaning that a modern web page may contain hundreds of tab stops. The question then is, how to improve UX and web accessibility at the same time for your Angular app? This article will help you figure it out. What is website accessibility Why website accessibility is important Page tab sequence and ARIA support Active element navigation Tab navigation Performance improvements and code enhancements Keyboard navigation features integration What Is Website Accessibility? The Internet is for everyone and website accessibility is key. Basically, web accessibility (or eAccessibility) is a practice that if well-established will make any website usable for all types of visitors and on any type of devices, regardless of things like: User tech know-how or previous experience with the World Wide Web. People who use assistive technologies. Speed and bandwidth. Use/No use of mouse. This is an extremely important goal to achieve by any web app/website because when they are designed and developed in the best possible way, more users have the same access to its content and functionalities. Why Is Website Accessibility Important? At Infragistics, we want to ensure an 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 within our Ignite UI for Angular Grid. This pattern reduces the number of tab stops within the interface designed for the igxGrid 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 Angular Grid element container by simply using the arrow keys. Thus, simplifying navigation and improving website usability. One of the biggest differentiators for our Ignite UI toolbox is that, unlike other grids on the market, we put end-users and their experience at the forefront of everything. That’s why we ensure component and feature parity across all major technologies. Meaning that whatever you do in Angular Grid, can be done and easily transitioned to Ignite UI for Blazor or Web Components as well. There won’t be any difference. So, if you care about your users, Ignite UI is the solution. What is ARIA Support? In short, ARIA stands for Accessible Rich Internet Application and is a set of attributes that is added to your HTML elements, making web apps and web content available to every user. ARIA support, then, is the capabilities of technologies, browsers, screen readers, and toolkits to support at least some of the ARIA properties. Page Tab Sequence and Aria 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. 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 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. This 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 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 must 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'). This is where the Active element navigation concept kicks in Here, the 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 from 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, the thick orange border with the gray cell background indicates the current active element for visual users. 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). Key takeaways from the sections above: 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 Ignite UI for Angular Grid as well: grid, row, grid cell, row header, and column header. Tab Navigation The grid follows the primary keyboard navigation convention that the tab and shift + 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. Compared to previous tab interaction behavior, we've changed the following: You cannot use the tab key to navigate between the cells in the IgxGrid. The navigation is now performed only with arrow keys. With the 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 the next row's editable cell. If the last editable cell is reached, the tab navigation will continue to the next focusable tab stop element. The Performance Improvements & Code Enhancements We Did As a result of the new keyboard navigation concept, we have been able to optimize our code and implement performance improvements in the Ignite UI for Angular Grid. They include: Removed cell focus and blur handlers. Wheel and view detach handlers have been removed as well. Reduced navigation services. We previously had four navigation services for the Grid, HierarchicalGrid, TreeGrid, 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). But there was a problem with the browser not allowing us to focus on an already focused element. We 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, { ngZoneEnetCoalescing: true }); Keyboard Navigation Features Integration Let's focus on the keyboard navigation features integration. Our Angular Grid has plenty of features and we've considered all of them carefully to ensure that they work properly with the new changes. Header navigation We now have a smooth column header and column group navigation. Check out this header interactions list, which explains how to activate a certain feature with a key combination. Live demo. Excel-style filter and default filtering row Ctrl + Shift + L will open the Excel-style filter/default (row) filter. Advanced filtering Alt + L opens the advanced filter dialog. Sorting 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). Group by 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). Multi-column headers Alt + left/up arrow key – collapse. Alt + right/down arrow key – expand. Column Selection Space key press - select a column. Note: If you are using a screen-reader, keep in mind that on an initial header click, we focus 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. Then the navigation will continue to the next available tab stop element. Filtering (filtering chips) - Tab navigation for chips is removed, so 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 website 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 different 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. To Conclude... We understand the need for continuous innovation and that great features are a result of true collaboration. Thanks to the combined efforts of our developers, we’ve managed to significantly reduce keyboard navigation complexity when using Ignite UI for Angular Grid (but also in every other grid in major technologies, keeping feature an component parity in mind). The overall keyboard interaction is now improved, intuitive to use, offering better website usability while ensuring website accessibility. 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 Comments section below.