How to create fully accessible nested dropdown lists using WAI-ARIA?

谁说我不能喝 提交于 2019-12-03 21:32:42

My 2c is that aria-controls may be a better fit here.

The UI you are describing here sounds very similar to the Country/State selects that you often find when purchasing a product online. A typical pattern for these is:

<label for="country">Country:</label>
<select id="country" aria-controls="state">
    <option value="">Select a country...</option>
    <option value="Andorra">Andorra</option>
    <option value="Belgium">Belgium</option>
    ...
</select>
<br>
<label for="state">State:</label>
<select id="state">
    <option value="">(Select a country first)</option>
    ... options here populated when country changes ...
</select>

A couple of things to note here:

  • I'm using 'placeholder' option entries at the start of each select. This has two benefits. First, it provides reinforcement documentation about how the user should use the UI - if they somehow end up looking at the second field first, it will direct them to the first one. Secondly, it avoids the user accidentally selecting a default value: your code can check if the default 'Select...' is the one submitted and remind the user to pick an actual value. And, additionally, it hides the fact that the contents options are changing from the user.

  • The main thing here, though, is that the relationship between these two selects should be clear from context in the form or page. Sighted or not, a user who encounters a form like this won't need to be explicitly told that the contents of the state select have changed, because they'll expect that from the form design, and from the context. People know that states are specific to a country (there's no "California" in Germany, for example), similarly with counties, so there's already an expectation of how these work.

Use of aria-live doesn't feel like it's appropriate here. It's really designed for areas of the page that update asynchronously, and which the user would otherwise have to poll continuously, reading back and forth, to scan for changes. Chat panels are perhaps the classic example: when a message appears from someone on the other end, you want the screenreader to read out the message when it appears, and not have to manually go hunting for it. By contrast, the UI here is more synchronous; when the country changes, the states are populated there and then(*), it's expected behavior.

ARIA does have an aria-controls="ids..." attribute, which seems to be a better fit: the spec says it's used for when one control affects the visibility or contents of another, which seems to describe what's happening here. I don't know offhand whether any screenreaders support this yet or what they would read out when its present - I may look into this and update this answer later. But in any case, the main point from earlier applies, the form's behavior and semantics should be apparent without this anyhow.

--

(*) There's still an issue that if you update the content asynchronously - eg. by getting the list of counties via ajax rather than from an array that's already loaded on the page, then there could be a delay between selecting the country and the results becoming available for use in the next select. aria-live doesn't feel like the right solution here again, since you don't want to read out the new content, you just want to let the user know that the select is now ready for use.

For this use case, I would add aria-live and aria-atomic attributes, example code:

<select id="foo" aria-live="assertive" aria-atomic="true">
    <option value="nw">Northwest</option>
    <option value="ne">Northeast</option>
    <option value="se">Southeast</option>
    <option value="sw">Southwest</option>
</select>

I think assertive is the right value for the aria-live attribute, but polite might be appropriate instead. The aria-atomic attribute is there to tell the browser/AT that region must be presented as a whole when there is a change. You might also consider using aria-disabled: true on the select initially, then switch it to false before you update it with the values associated with the State select.

Edit

OK, I've done some testing using NVDA and IE9 and Firefox 13.01. I don't have JAWS available at the moment, so it'd be great if someone could test the page with JAWS. VoiceOver as far as I know doesn't have support for aria properties yet Just tested with Chrome + Voiceover on 10.7 (Lion) and Voiceover does indeed appear to have support for aria-live.

Test page available here.

I used a simple script that simulated loading data into the regions select (using an object):

var options = [],
    regions = {
    'nw': 'Northwest',
    'ne': 'Northeast',
    'se': 'Southeast',
    'sw': 'Southwest'
}

$(document).ready(function() {
    $.each(regions, function(key, value) {
        options.push('<option value="'+ key +'">'+ value +'</option>');
    });

    $('.block').on('change, focusout', '.states', function() {
        $(this).parent().children('.regions')
            .attr({'disabled': false, 'aria-disabled': false})
            .html(options.join(''));
    });

    window.setTimeout(
        function() {
            $('#speak').text('assertive!');
        },
        3000
    );
});

Some observations after playing with this a bit (I'm certainly no expert when it comes to screen readers, so if I missed something let me know)...

  • Using the HTML disabled attribute is not advised as you really don't want to load the region data until the state select is focused out and since the associated region select is disabled at the time of the focusout it is skipped when tabbing to the next control (you can hear this in the recordings below.) Strangely, Firefox announces the value of the region select even though it doesn't focus it.

  • I saw no difference in behavior between polite and assertive, or for that matter in the example without the aria-live attribute. I thought that both FF13 and IE9 had support for aria-live, but from the last but of code ($('#speak')...) it appears that IE9 doesn't?

  • Perhaps a delay to simulate loading via AJAX would be a good thing to add.

You can listen to the recordings: IE9, Firefox 13

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!