Angular Tree Grid Keyboard Navigation

    Keyboard navigation in the IgxTreeGrid provides a rich variety of keyboard interactions for the user. It enhances the accessibility of the IgxTreeGrid and allows to navigate through any type of elements inside (cell, row, column header, toolbar, footer, etc.). This functionality is enabled by default, and the developer has the option to override any of the default behaviors in an easy way.

    The tabulations of the IgxTreeGrid has been reduced so that the navigation is compliant with W3C accesibility standards and convenient to use.

    Currently, the IgxTreeGrid introduces the following tab stops:

    • GroupBy or Toolbar area (if enabled);
    • IgxTreeGrid header;
    • IgxTreeGrid body;
    • Column summaries (if enabled);
    • IgxTreeGrid paginator (if enabled);
    Note

    Due to this change, navigating between the cells with tab and Shift + Tab is no longer supported in the IgxTreeGrid. Pressing the Tab key now goes through the tab stops in the following order: GroupBy / Toolbar -> Headers -> Body -> Summaries -> Footer / Paginator.

    Note

    Exposing any focusable element into the IgxTreeGrid body via template may introduce side effects in the keyboard navigation, since the default browser behavior is not prevented. It is the developer's responsibility to prevent or modify it appropriately.

    Header Navigation

    A full keyboard navigation support in the IgxTreeGrid header is now introduced. Column headers can be easily traversed with the arrow keys. Additionally, there are a number of key combinations that trigger actions on the columns like filtering, sorting, grouping and etc. When the IgxTreeGrid header container is focused, the following key combinations are available:

    Key Combinations

    • Arrow Up navigates one cell up in the headers (no looping). Available only when Multi-row Layout (MRL) or Multi-column Headers (MCH) are defined
    • Arrow Down navigates one cell down in the headers (no wrapping). Available only when Multi-row Layout (MRL) or Multi-column Headers (MCH) are defined
    • Arrow Left navigates one cell left (no looping)
    • Arrow Right navigates one cell right (no wrapping between lines)
    • Ctrl + Arrow Left navigates to the leftmost cell in the row; if MRL or MCH are enabled, navigates to the leftmost cell at the same level
    • Home navigates to the leftmost cell in the row; if MRL or MCH are enabled, navigates to the leftmost cell at the same level
    • Ctrl + Arrow Right navigates to the rightmost cell in row; if MRL or MCH are enabled, navigates to the rightmost cell at the same level
    • End navigates to the rightmost cell in row; if MRL or MCH are enabled, navigates to the rightmost cell at the same level
    • Alt + L opens Advanced Filtering dialog if Advanced Filtering is enabled
    • Ctrl + Shift + L opens the Excel Style Filter dialog or the default (row) filter if the column is filterable
    • Ctrl + Arrow Up sorts the active column header in ASC order. If the column is already sorted in ASC, sorting state is cleared
    • Ctrl + Arrow Down sorts the active column header in DSC order. If the column is already sorted in DSC, sorting state is cleared
    • Space selects the column; If the column is already selected, selection is cleared

    Body navigation

    When the IgxTreeGrid body is focused, the following key combinations are available:

    Key Combination

    • Arrow Up- navigates one cell up (no wrapping)
    • Arrow Down navigates one cell down (no wrapping)
    • Arrow Left navigates one cell left (no wrapping between lines)
    • Arrow Right - navigates one cell right (no wrapping between lines)
    • Ctrl + Arrow Left navigates to the leftmost cell in the row
    • Ctrl + Arrow Right navigates to the rightmost cell in the row
    • Ctrl + Arrow Up navigates to the first cell in the column
    • Ctrl + Arrow Down navigates to the last cell in the column
    • Home navigates to the leftmost cell in the row
    • End navigates to the rightmost cell in the row
    • Ctrl + Home navigates to the top leftmost data cell in the grid
    • Ctrl + End navigates to the bottom rightmost data cell in the grid
    • Page Up scrolls one page (view port) up
    • Page Down scrolls one page (view port) down
    • Enter enters edit mode
    • F2 enters edit mode
    • Esc exits edit mode
    • Tab available only if there is a cell in edit mode; moves the focus to the next editable cell in the row; after reaching the last cell in the row, moves te focus to the first editable cell in the next row. When Row Editing is enabled, moves the focus from the right-most editable cell to the CANCEL and DONE buttons, and from DONE button to the left-most editable cell in the row
    • Shift + Tab - available only if there is a cell in edit mode; moves the focus to the previous editable cell in the row; after reaching the first cell in the row, moves the focus to the last editable cell in the previous row. When Row Editing is enabled, moves the focus from the right-most editable cell to CANCEL and DONE buttons, and from DONE button to the right-most editable cell in the row
    • Space - selects the row, if Row Selection is enabled
    • Alt + Arrow Left or Alt + Arrow Up - collapses the current node
    • Alt + Arrow Right or Alt + Arrow Down - expands the current node

    Practice all of the above mentioned actions in the demo sample below. Focus any navigable grid element and a list with some of the available actions for the element will be shown to guide you through.

    Demo

    Custom keyboard navigation

    Overriding the default behavior for a certain key or keys combination is one of the benefits that the Keyboard Navigation feature provides. For example: press the Enter or Tab key to navigate to the next cell or the cell below. This or any other navigation scenario is easily achieved by the Keyboard Navigation API:

    API Description Arguments
    gridKeydown An event that is emitted when any of key press/combinations described above is performed. Can be canceled. For any other key press/combination, use the default onkeydown event. IGridKeydownEventArgs
    activeNodeChange An event that is emitted when the active node is changed. You can use it to determine the Active focus position (header, tbody etc.), column index, row index or nested level. IActiveNodeChangeEventArgs
    navigateTo Navigates to a position in the grid, based on provided rowindex and visibleColumnIndex. It can also execute a custom logic over the target element, through a callback function that accepts param of type { targetType: GridKeydownTargetType, target: Object } . Usage:
    grid.navigateTo(10, 3, (args) => { args.target.nativeElement.focus(); });
    rowindex: number, visibleColumnIndex: number, callback: ({ targetType: GridKeydownTargetType, target: Object }) => {}
    getNextCell returns ICellPosition object, which defines the next cell by rowIndex and visibileColumnIndex. A callback function can be passed as a third parameter of getNextCell method. The callback function accepts IgxColumnComponent as a param and returns a boolean value indication if a given criteria is met:
    const nextEditableCell = grid.getNextCell(0, 4, (col) => col.editable);
    currentRowIndex: number, currentVisibleColumnIndex: number, callback: (IgxColumnComponent) => boolean
    getPreviousCell returns ICellPosition object, which defines the previous cell by rowIndex and visibileColumnIndex. A callback function can be passed as a third parameter of getPreviousCell method. The callback function accepts IgxColumnComponent as a param and returns a boolean value indication if a given criteria is met:
    const prevEditableCell = grid.getPreviousCell(0, 4, (col) => col.editable);
    currentRowIndex: number, currentVisibleColumnIndex: number, callback: (IgxColumnComponent) => boolean

    Let's try the API to demonstrate how to achieve common scenarios like user input validation and custom navigation. First we need to register an event handler for the gridKeydown event:

    <igx-tree-grid #grid1 [data]="data" (gridKeydown)="customKeydown($event)">
    </igx-tree-grid>
    
    public customKeydown(args: IGridKeydownEventArgs) {
        const target: IgxGridCell = args.target as IgxGridCell;
        const evt: KeyboardEvent = args.event as KeyboardEvent;
        const type = args.targetType;
    
        if (type === 'dataCell' && target.inEditMode && evt.key.toLowerCase() === 'tab') {
            // 1. USER INPUT VALIDATON ON TAB
        }
        if (type === 'dataCell' && evt.key.toLowerCase() === 'enter') {
            // 2. CUSTOM NAVIGATION ON ENTER KEY PRESS
        }
    }
    

    Based on the IGridKeydownEventArgs values we identified two cases, where to provide our own logic (see above). Now, using the methods from the API, let's perform the desired - if the user is pressing Tab key over a cell in edit mode, we will perform validation on the input. If the user is pressing Enter key over a cell, we will move focus to cell in the next row:

        // 1. USER INPUT VALIDATON ON TAB
        if (target.column.dataType === 'number' && target.editValue < 18) {
            // alert the user that the input is invalid
            return;
        }
        // 2. CUSTOM NAVIGATION ON ENTER KEY PRESS
        const nexRowIndex = target.row.expanded ? target.rowIndex + 2 : target.rowIndex + 1;
        grid.navigateTo(nexRowIndex, target.visibleColumnIndex,
            (obj) => { obj.target.nativeElement.focus(); });
    

    Note: Please refer to the sample code for full implementation details.

    Use the demo below to try out the custom scenarios that we just implemented:

    • Double click or press F2 key on a cell in the Age column, change the value to 16 and press tab key. Prompt message will be shown.
    • Select a cell and press Enter key a couple of times. Every key press will move the focus to a cell in the next row, under the same column.

    Known Limitations

    Limitation Description
    Navigating inside а grid with scrollable parent container. If the grid is positioned inside a scrollable parent container and the user navigates to a grid cell that is out of view, parent container will not be scrolled.

    API References

    Additional Resources

    Our community is active and always welcoming to new ideas.