TODOs
ARIA and DOM setup
div[role="combobox"]
- Inside, an
input
- A
ul (ideally, the next sibling element but can be inside a portal if it must)
- Somewhere on the page, a
p
- Somewhere on the page, a
p
Focus and keyboard controls
- TAB
- ESC
- DOWN_ARROW
- UP_ARROW
- ENTER
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
TODOs
ARIA and DOM setup
div[role="combobox"]aria-expanded={isResultsListOpen}aria-owns={collectionId}aria-haspopup="listbox"Δinputlabel[for="inputId"]oraria-labelautocomplete="off"aria-expanded="{isResultsListOpen}"§role="combobox"§aria-autocomplete="list"†aria-controls="{collectionId}"aria-haspopup="listbox"Δ§aria-activedescendant="{descendantId}"‡aria-describedby="{uniqueId-info} {uniqueId-instructions}"ul(ideally, the next sibling element but can be inside a portal if it must)role="listbox"id="{collectionId}"label(usingaria-labelledby) oraria-labelas for the inputliwith arole="option",aria-selected={isCurrentlyFocusedOption}and anid(That gets used as thedescdendantIdmentioned above; it can be one, static ID that moves to the appropriatelior individual IDs perliwhich then gets updated at thearia-activedescendantattribute)pid="{uniqueId-info}"pid="{uniqueId-instructions}"Focus and keyboard controls
input§aria-activedescendantto the first optionaria-activedescendantto the next optionaria-activedescendantto the first option (i.e., wrap around)aria-activedescendantto the previous optionaria-activedescendantto the last option (i.e., wrap around)Notes
† Swapping the value of
aria-autocompleteisn'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
listboxhere instead ofgridwhich would also be appropriate to simplify both the implementation and the user interaction. Becausegridpopups 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-activedescendantvs 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 thebody, 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
aria-autocompletespecaria-haspopupspecaria-activedescendantaria-expanded