Skip to content

[EuiSuggest] Accessibility #2404

@myasonik

Description

@myasonik

TODOs

ARIA and DOM setup

  • div[role="combobox"]
    • aria-expanded={isResultsListOpen}
    • aria-owns={collectionId}
    • aria-haspopup="listbox"Δ
  • Inside, an input
    • labelled by a label[for="inputId"] or aria-label
    • autocomplete="off"
    • aria-expanded="{isResultsListOpen}"§
    • role="combobox"§
    • aria-autocomplete="list"
    • aria-controls="{collectionId}"
    • aria-haspopup="listbox"Δ§
    • aria-activedescendant="{descendantId}"
    • aria-describedby="{uniqueId-info} {uniqueId-instructions}"
  • A ul (ideally, the next sibling element but can be inside a portal if it must)
    • role="listbox"
    • id="{collectionId}"
    • labelled by the same label (using aria-labelledby) or aria-label as for the input
    • Children are an li with a role="option", aria-selected={isCurrentlyFocusedOption} and an id (That gets used as the descdendantId mentioned above; it can be one, static ID that moves to the appropriate li or individual IDs per li which then gets updated at the aria-activedescendant attribute)
  • Somewhere on the page, a p
    • id="{uniqueId-info}"
    • Can be visually hidden
    • Communicates the state (draft, loading, saved)
  • Somewhere on the page, a p
    • id="{uniqueId-instructions}"
    • Can be visually hidden
    • Communicates basic instructions. Something like: "Use up and down arrows to move focus over options. Enter to select. Escape to collapse options."

Focus and keyboard controls

  • TAB
    • If an option is currently active, select the current option (same as ENTER) and moves focus (as it normally would)
    • If no option is active, collapse the listbox and move focus (as it normally would)
    • When tabbing through the widget, the only tab stop should be the input§
  • ESC
    • If the listbox is open, collapse the listbox
    • Optionally, clear the input field
    • Optionally, return the state of the typeahead to whatever it was before focus was set on the input
  • DOWN_ARROW
    • If the listbox is closed and there are options, expand the listbox and set aria-activedescendant to the first option
    • If the listbox is expanded and there are subsequent options, set aria-activedescendant to the next option
    • If the listbox is expanded and there are no subsequent options, set aria-activedescendant to the first option (i.e., wrap around)
  • UP_ARROW
    • If there is a previous option, set aria-activedescendant to the previous option
    • If there are no previous options, set aria-activedescendant to the last option (i.e., wrap around)
  • ENTER
    • If an option is currently active, select the option, collapsing the listbox and clearing the input field

Notes

† Swapping the value of aria-autocomplete isn't supposed to be a dynamic thing but the spec is vague on how to handle dynamic results. It seems to work though so I think we roll with it.

Δ Using listbox here instead of grid which would also be appropriate to simplify both the implementation and the user interaction. Because grid popups are so much less common, it'll be a more difficult pattern for users to pick up.

‡ These properties follow the ARIA 1.0 spec, not the new ARIA 1.1 spec but the support is best to combine approaches

§ Using aria-activedescendant vs DOM focus is debatable. The spec is open to either implementation but I think this is the right decision based on our already TAB heavy interfaces, general lack of strong accessible navigation controls around apps, has a lower chance of throwing a user's focus back to the body, and supports a wider array of possible interfaces (e.g., adding controls at the bottom of results like saved searches wanted to do in an earlier draft UI).

An incomplete example

https://codepen.io/myasonik/pen/LYYEYXb?editors=0010


References

Metadata

Metadata

Assignees

Labels

accessibilitymetaUsed to group similar requests or tracking. Not an Epic.

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions