Skip to content

Commit

Permalink
Make query bar autocomplete screen reader accessible (#20740)
Browse files Browse the repository at this point in the history
Fixes #20099

I made the changes described by Tim at #20099 and everything seems to be working. I tried to update the typeahead in such a way that it can be made accessible anywhere it is used, even if there are multiple typeahead instances on a single page.

> (optional) an aria-label on the individual suggestions that should be read out to screen reader. By default the content will be used, and that should be fine (unless you figure out there is too much "noise" elements in it.

I did not do this bit since the text that is read seems reasonable to me, but I'm open to changing it if others feel differently.
  • Loading branch information
Bargs authored Aug 9, 2018
1 parent da1268d commit e0fba82
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 6 deletions.
10 changes: 10 additions & 0 deletions src/ui/public/query_bar/directive/query_bar.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
<kbn-typeahead
items="queryBar.suggestions"
item-template="queryBar.suggestionTemplate"
id="query-bar-suggestions"
on-select="queryBar.onSuggestionSelect(item)"
on-focus-change="queryBar.focusedTypeaheadItemID = $focusedItemID"
class="suggestionTypeahead"
>
<div
Expand All @@ -30,6 +32,10 @@
class="kuiLocalSearchInput"
ng-class="{'kuiLocalSearchInput-isInvalid': queryBarForm.$invalid}"
data-test-subj="queryInput"
aria-autocomplete="list"
aria-controls="query-bar-suggestions-typeahead-items"
aria-activedescendant="{{queryBar.focusedTypeaheadItemID}}"
role="textbox"
>

<!-- kuery input -->
Expand All @@ -51,6 +57,10 @@
class="kuiLocalSearchInput"
ng-class="{'kuiLocalSearchInput-isInvalid': queryBarForm.$invalid}"
data-test-subj="queryInput"
aria-autocomplete="list"
aria-controls="query-bar-suggestions-typeahead-items"
aria-activedescendant="{{queryBar.focusedTypeaheadItemID}}"
role="textbox"
/>
<div class="kuiLocalSearchAssistedInput__assistance">
<query-popover
Expand Down
1 change: 1 addition & 0 deletions src/ui/public/query_bar/directive/query_bar.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ module.directive('queryBar', function () {

controller: callAfterBindingsWorkaround(function ($scope, $element, $http, $timeout, config, PersistedLog, indexPatterns) {
this.appName = this.appName || 'global';
this.focusedTypeaheadItemID = '';

this.getIndexPatterns = () => {
if (compact(this.indexPatterns).length) return Promise.resolve(this.indexPatterns);
Expand Down
10 changes: 5 additions & 5 deletions src/ui/public/query_bar/directive/suggestion.html
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
<div class="suggestionItem suggestionItem--{{item.type}}">
<div class="suggestionItem__type">
<div ng-switch="item.type">
<div ng-switch-when="field">
<div ng-switch-when="field" aria-label="Field">
<icon type="'kqlField'"></icon>
</div>
<div ng-switch-when="value">
<div ng-switch-when="value" aria-label="Value">
<icon type="'kqlValue'"></icon>
</div>
<div ng-switch-when="recentSearch">
<div ng-switch-when="recentSearch" aria-label="Recent search">
<icon type="'search'"></icon>
</div>
<div ng-switch-when="conjunction">
<div ng-switch-when="conjunction" aria-label="Conjunction">
<icon type="'kqlSelector'"></icon>
</div>
<div ng-switch-when="operator">
<div ng-switch-when="operator" aria-label="Operator">
<icon type="'kqlOperand'"></icon>
</div>
</div>
Expand Down
8 changes: 8 additions & 0 deletions src/ui/public/typeahead/typeahead.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
class="typeahead"
ng-keydown="typeahead.onKeyDown($event)"
ng-keypress="typeahead.onKeyPress($event)"
role="combobox"
aria-haspopup="true"
aria-owns="{{typeahead.elementID}}-typeahead-items"
aria-expanded="{{typeahead.isVisible() ? true : false}}"
>
<ng-transclude></ng-transclude>
<div
Expand All @@ -13,13 +17,17 @@
<div
class="typeahead-items"
kbn-scroll-bottom="typeahead.increaseLimit()"
role="listbox"
id="{{typeahead.elementID}}-typeahead-items"
>
<div
class="typeahead-item"
ng-repeat="item in typeahead.items | limitTo: typeahead.limit"
ng-class="{active: $index === typeahead.selectedIndex}"
ng-click="typeahead.onItemClick()"
ng-mouseenter="typeahead.selectedIndex = $index"
role="option"
id="{{typeahead.elementID}}-typeahead-item-{{$index}}"
>
<kbn-typeahead-item
item="item"
Expand Down
8 changes: 7 additions & 1 deletion src/ui/public/typeahead/typeahead.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,15 @@ typeahead.directive('kbnTypeahead', function () {
scope: {
items: '=',
itemTemplate: '=',
onSelect: '&'
onSelect: '&',
onFocusChange: '&'
},
bindToController: true,
controllerAs: 'typeahead',
controller: function ($scope, $element) {
this.isHidden = true;
this.selectedIndex = null;
this.elementID = $element.attr('id');

this.submit = () => {
const item = this.items[this.selectedIndex];
Expand Down Expand Up @@ -137,6 +139,10 @@ typeahead.directive('kbnTypeahead', function () {
this.onMouseLeave = () => {
this.isMousedOver = false;
};

$scope.$watch('typeahead.selectedIndex', (newIndex) => {
this.onFocusChange({ $focusedItemID: newIndex !== null ? `${this.elementID}-typeahead-item-${newIndex}` : '' });
});
}
};
});

0 comments on commit e0fba82

Please sign in to comment.