I have a role="grid"
table with some cells sharing the same content (e.g. text, number or date).
Clicking a cell means changing the selected state of the value in the cell, which is visually displayed by a different border color around the cell. This selection can also be controlled via keyboard (e.g. Control + Space) as described for the ARIA grid pattern.
When a cell (actually it's value) is selected, along with it, all other cells with the same value are also selected.
All selected cells get set the attribute aria-selected="true"
(false
if not selected).
When toggling the selection of a cell (its value) the backend is asked via AJAX request to confirm this and provide some actions. While waiting the cursor is changed to wait
on the table.
When the actions arrive from the backend, a popup menu is opened and visually attached to the last clicked cell.
What ARIA attributes must I add to the cells also?
Corresponding questions:
aria-haspopup="menu"
fine and compatible with aria-selected="true"
change?aria-expanded
and aria-controls
?aria-expanded="true"
at first when getting the response?Good question, it’s great that you are looking into proper use of ARIA!
You’re on a good track with your questions, I’m just afraid that there is a hick-up with the use of selection to trigger an action, which impedes correct use of aria attributes. This is reflected in your first question:
Is
aria-haspopup="menu"
fine and compatible witharia-selected="true"
change?
No, a change of aria-selected
is not expected to change aria-expanded
. That might not be explicitly documented, but is a convention:
Selecting items usually is a manual, intermediary step for the user, before executing an action on that selection. Selecting items shouldn’t trigger anything, especially not changing the set of selected items. That’s unexpected.
Case in point: to my knowledge, assistive technologies have no mechanism to communicate to the user what other cells have been auto-selected, as the state change would only be announced for the grid cell under focus.
My recommendation here would be to work with an action on the value, rather than a selection.
Activating the item would open the menu, and we can find good orientation on the Menu Button Pattern, including the use of aria-haspopup
and aria-expanded
.
While it would be possible to use the cell itself as the triggering element (<td aria-haspopup="menu">
), I’d recommend the use of a button within the cell to make it more obivous.
In the end, anything discoverable by means of ARIA attributes, should also be made obvious visually and for users of pointer devices. Clicking a cell is not expected.
This, then, raises the question Whether to Focus on a Cell Or an Element Inside It. The APG mention:
A cell contains one widget whose operation does not require arrow keys and grid navigation keys set focus on that widget. Examples of such widgets include […] button […]
<td><button aria-expanded="false" aria-haspopup="menu" tabindex="-1">Germany</button></td>
So you should make sure focus is set on the button with the arrow keys, rather than the cell.
The selected state currently helps the user determine which rows will be affected by the actions.
If a visual hint is enough, you could add a style to highlight these rows.
<td class="highlight"><button …>Germany</button></td>
If more guidance is necessary to prevent mistakes, you might want to consider these to options:
aria-haspopup="dialog"
) that lists the affected companies, along with the final actions.aria-selected
rows as the result of the action triggered by the country as an intermediary step, but offering the final actions outside the table. This would allow users of assistive technology to review the set of companies before executing the actions.What if the backend decides that no actions are available and so no menu is shown?
If the backend cannot deliver the information whether actions are available for a country along with the data for the grid, you should still open the pop-up, because feedback to the user’s action is always necessary (within 150 ms), a change to aria-expanded="true"
is expected.
Do I need
aria-expanded
andaria-controls
?
You must use the former, and should use the latter, but only once the pop-up becomes visible.
Do I need to indicate the loading state of the menu somehow (waiting for backend's actions)?
Visibility of system state is important, so while waiting for the response, you would show a loading indicator within the menu pop-up, and set focus on the menu, which can provide the loading state in its name for assistive technology.
To summarise:
Open the menu pop-up, set aria-expanded="true"
and aria-controls
on the button.
Set focus to the empty menu, with a loading animation.
When the backend response arrives, insert the delivered menu items and change the pop-up’s name.
Set focus to the first new item. If the result is empty, provide a disabled menu item stating so.
and then
<ul aria-label="Actions for Germany" role="menu" aria-busy="false">
<li role="menuitem" aria-disabled="true">No actions available</li>
</ul>
The use of aria-busy
here is optional, it doesn’t have much support currently, and if the actions arrive in one response, it doesn’t change much whether the empty contents are announced before.
The popup exists at first when we get the actions from backend. Do I set
aria-expanded="true"
at first when getting the response?
Visibility of the pop-up and the ARIA state must be set together. You might not show the pop-up while loading, but showing system status then would be difficult.
The APG actually mention that
Control + Space: selects the column that contains the focus.
(emphasise mine)
but the Grid pattern doesn’t mention how one would select a single cell. One needs to dive into the practices of Developing a Keyboard Interface to find the answer:
When selection does not follow focus, the user changes which element is selected by pressing the Enter or Space key.