I am looking for a way to make JAWS (and probably other screen readers) announce the unfocused element. I am having a contenteditable
area which after typing certain characters opens autocomplete/suggestion panel. The focus stays inside contenteditable
to enable further typing while the panel is open showing possible suggestion. The JAWS does not announce the panel appearance because it is not focused.
If the focus is forced on the panel JAWS announces it correctly (role="listbox"
) but of course it breaks the autocomplete functionality.
I created a very simple sample which illustrates the problem:
var editable = document.querySelector('#editable'),
list = document.querySelector('#list'),
counter = 0;
editable.addEventListener('keypress', function(evt) {
counter++;
if (counter > 5) {
list.style.display = 'block';
list.setAttribute("aria-expanded", true);
// Focusing list works fine and JAWS announces everything correctly, but then the contenteditable loses focus and typing cannot be continued which is crucial for autocompleting functionality.
setTimeout( function() { list.focus() }, 0 ); // Comment out this line to see/hear the difference.
}
});
div {
width: 400px;
height: 300px;
border: 1px solid #000;
}
.autocomplete_panel {
position: absolute;
display: none;
box-sizing: border-box;
width: 200px;
max-height: 300px;
overflow: auto;
padding: 0;
margin: 0;
list-style: none;
background: #FFF;
border: 1px solid #b6b6b6;
border-bottom-color: #999;
border-radius: 3px;
font: 12px Arial, Helvetica, Tahoma, Verdana, Sans-Serif;
}
#label_00 {
display: none;
}
<div role="application">
<div contenteditable="true" id="editable">
Type sth to show panel...
</div>
<ul id="list" tabindex="-1" role="listbox" aria-labelledby="label_00" class="autocomplete_panel" style="z-index: 9997; left: 150px; top: 20px;">
<li data-id="1" role="option" aria-posinset="1" aria-setsize="4">Item 1</li>
<li data-id="2" role="option" aria-posinset="2" aria-setsize="4">Item 2</li>
<li data-id="3" role="option" aria-posinset="3" aria-setsize="4">Item 3</li>
<li data-id="4" role="option" aria-posinset="4" aria-setsize="4">Item 4</li>
<li aria-hidden="true" id="label_00">Autosuggestion panel</li>
</ul>
</div>
JSfiddle version: https://jsfiddle.net/f1ames/op15mm8z/.
Some solutions I am considering but are not perfect:
Use hidden span with
aria-live
and dynamic text (with similar/same text to native JAWS announcement):- inconsistency between screen readers (different announcements for
listbox
in different screen readers) - won't be based on screen reader language (it should)
- not flexible (JAWS may have different setting so announcements may vary - native JAWS announcement would be much better)
- inconsistency between screen readers (different announcements for
Focusing autocomplete panel:
- should still support typing inside
contenteditable
which may be very tricky especially for some unicode characters and composition - when focus gets back to
contenteditable
the announcement of autocomplete will be aborted
- should still support typing inside
Providing aria-markup to make JAWS properly announce autocomplete panel:
aria-live
andaria-atomic
works to some extend but therole
is not supported. JAWS reads onlyaria-labelledby
element or list items as plain text (difference foraria-atomic='true/false'
)
So at the moment I am not aware of any method to make JAWS announce the unfocused element same way as if it was focused. Any thoughts?
Btw. aria practices for autocomplete: https://www.w3.org/TR/wai-aria-practices/#autocomplete.