ARIA’s list and listitem roles allow for developers to change the semantics of other HTML tags to announce themselves as lists, and items within a list, respectively.

More often than not, using native ul, or ol, elements is the ideal method to markup each type of list (I didn’t forget about dls. I’m going to talk about those another day). But there may be times when native elements can’t be used, or you’re stuck working with a sea of legacy or 3rd party divs, and you’ll need to lean on ARIA to modify a document’s markup to be more semantic and accessible.

Ordered, unordered, it’s all the same to ARIA

Since ARIA role="list" is based on the native HTML ol and ul elements, one might wonder how it could announce itself as one or the other? Well, it can’t. But that’s OK, because if you navigate to native ol and ul elements with screen readers, you’ll notice each list type doesn’t immediately announce themselves as either an ordered or unordered list. The type of list becomes clear once you start interacting with the different list items within. By default, these native list items will have a number announced for ordered lists, and a “bullet” for unordered lists.

Providing the context to the type of list an ARIA list is meant to represent can be done with CSS.

CSS for “unordered” listitems

As ARIA only affects the semantics of a HTML tag, and not its native functionality or appearance, there are no bullets for screen readers to pick up on to announce.

For unordered listitems, this may not be an issue for simple lists, as each listitem can still be navigable by screen reader quick keys (more on that later).

But if dealing with nested unordered lists, it’d be optimal to provide an audible cue that would allow users to easily identify the nested list they are in.

To add “bullets” or other list styles to a listitem, the following CSS would be needed:

[role="listitem"] {
  display: list-item;
}

.pretend-ul [role="listitem"] {
  list-style: disc; /* default bullet */
}

/* a nested list should have a different glyph */
.pretend-ul [role="listitem"] [role="listitem"] {
  list-style: circle; 
}

/* and etc. */
.pretend-ul [role="listitem"] [role="listitem"] [role="listitem"] {
  list-style: square; 
}

CSS for “ordered” listitems

Where it’s fairly straight forward to add non-incremental glyphs to unordered listitems (straight forward being a relative term in regards to how many nested lists you have to support), if you try to add list-style: decimal; to mimic an ordered list, you’ll notice it doesn’t work out so well.

To get around listitems not auto-incrementing like native list items do, CSS counters can be used instead.

The following example demonstrates an ARIA list with CSS counters used to add in the increments.

ARIA "ordered list" example

Test
Test again

(This example and more can be viewed here: Ordered ARIA lists using CSS counters CodePen.)

As with many other things not supported by Internet Explorer, screen readers paired with IE won’t announce the CSS counters. But testing with NVDA & JAWS in Chrome, and Firefox, as well as VoiceOver & Safari (desktop and mobile), will announce the counters largely as if they were native list items of an ol element.

Grouping list items

Where a native ol or ul element can only have li elements as direct children, an ARIA list has a looser expectation for child elements since the native semantics and markup expectations for the native lists won’t apply.

As an example, the following markup pattern is valid for an ARIA list:

<div role="list">
  <div role="presentation">
    <div role="listitem">...</div>
    <div role="listitem">...</div>
  </div>
  <div role="presentation">
    <div role="listitem">...</div>
    <div role="listitem">...</div>
  </div>
</div>

The role="presentation" is necessary to appropriately convey the number of listitems to NVDA + Firefox. Without the role="presentation", NVDA would only announce the “list” as having “two” items within it, though each of the listitems would still be navigable by quick keys.

Speaking of Announcements

If you want to test how different screen readers interpret ARIA lists, you can check out the following CodePens:

Unordered ARIA lists announcements

If you don’t have access to a bunch of devices and screen readers, here is a summary per how screen readers interact with list and listitems per the “Unordered ARIA lists” CodePen.

Native ul and ol announcements

Safari + VoiceOver (desktop High Sierra)

Focusing on the native list wrapper, VoiceOver will announce "list # items"

For ul list items, VoiceOver will announce "bullet, accessible name, x of y"

For `ol` list items, VoiceOver will announce "#, accessible name, # of y"

VoiceOver will announce when a user has reached the end of a list.

Safari + VoiceOver (iOS 11.3.1)

Navigating by lists with VoiceOver rotor, the first bullet or # will be focused when swiping up or down. Having VoiceOver announce "bullet, list start" or "#, list start".

For ul list items, VoiceOver will announce "bullet" and then require a second swipe to read the content of the list item.

For ol list items, VoiceOver will announce "#" and then require a second swipe to read the content of the list item.

When navigating to the last list item in a list, VoiceOver will announce "list end" after the content of the last list item is announced.

JAWS 2018 + Edge

Focusing on the native list wrapper, JAWS will announce "list of # items" and then immediately announce the first list item.

For ul list items, JAWS will announce "bullet, accessible name".

For ol list items, JAWS will announce "#, accessible name".

JAWS 2018 + IE11 / Firefox ESR / Firefox Nightly 62 / Latest Chrome

Focusing on the native list wrapper, JAWS will announce "list of # items".

For ul list items, JAWS will announce "bullet, accessible name".

For ol list items, JAWS will announce "#, accessible name".

NVDA 2018.1 + Firefox ESR / Firefox Nightly 62 / Latest Chrome

Focusing on the native list wrapper, NVDA will announce "list of # items" and then announce the first list item of the list, in the format of how NVDA announces individual list items.

For ul list items, NVDA will announce "bullet, accessible name".

For ol list items, NVDA will announce "#, accessible name".

ARIA list and listitem announcements

Safari + VoiceOver (desktop High Sierra)

For role=list with listitem elements without display: list-item VoiceOver will announce the accessible name, and the x of y for each list item.

If the listitem elements have display: list-item and a list-style: disc, VoiceOver will announce "bullet, accessible name, x of y" for each list item.

VoiceOver has no issues announcing or navigating "grouped" lists regardless of role="presentation" being used or not.

Safari + VoiceOver (iOS 11.3.1)

When navigating by lists with VoiceOver rotor:

For role="list" with listitem elements not set to display: list-item VoiceOver will announce the accessible name of the first list item, and then announce "list start".

If the listitem elements have display: list-item and a list-style: disc, VoiceOver will announce "bullet" and then "list start".

When navigating to the last list item in a list, VoiceOver will announce "list end" after the content of the last list item is announced.

VoiceOver has no issues announcing the number of items in a list, or navigating "grouped" lists regardless of role="presentation" being used or not.

JAWS 2018 + Edge

JAWS + Edge will navigate to an ARIA list by use of the l key. It will not announce the number of items within the list though...

And using i quick keys, JAWS + Edge do not recognize ARIA listitems.

When navigating by the virtual cursor, JAWS + Edge will announce a bullet if provided by CSS, so this is the only way to effectively convey a listitem to Edge users.

JAWS 2018 + IE11

Unlike Edge, IE11 does recognize both role=list and role=listitems.

Quick keys work to navigate by list or list item. When first navigating to a list, JAWS will announce how many items are within the list, but will not announce the current list item #, nor will it announce the bullets provided by display: list-item and a list-style: disc.

IE11 + JAWS have no issues announcing the number of items in a list, or navigating "grouped" lists regardless of role="presentation" being used or not.

JAWS 2018 + Firefox ESR & Firefox Nightly 62

Navigating to a list JAWS will announce "list of # items".

For role=list with listitem elements not set to display: list-item JAWS will announce the accessible name of each listitem.

If the listitem elements have display: list-item and a list-style: disc, JAWS will announce "bullet, accessible name" for each list item.

Firefox + JAWS have no issues announcing the number of items in a list, or navigating "grouped" lists regardless of role="presentation" being used or not. However, the CSS bullets are not announced.

JAWS 2018 + Chrome latest

Navigating to a list JAWS will announce "list of # items".

For role=list with listitem elements not set to display: list-item JAWS will announce the accessible name of each listitem. The virtual cursor will *not* visually highlight these list items, though no other issues with navigation seem to exist.

If the listitem elements have display: list-item and a list-style: disc, JAWS will announce "bullet, accessible name" for each list item.

Chrome + JAWS have no issues announcing the number of items in a list, or navigating "grouped" lists regardless of role="presentation" being used or not.

NVDA 2018.1 + Firefox ESR & Firefox Nightly 62

Navigating to a list NVDA will announce "list of # items" and then announce the first list item of the list, in the format of how NVDA announces individual listitem.

For role=list with listitem elements not set to display: list-item NVDA will announce the accessible name of each listitem.

If the listitem elements have display: list-item and a list-style: disc, NVDA will announce "bullet, accessible name" for each list item.

Firefox + NVDA will incorrectly announce the number of listitems in a list, if listitem wrappers do not have a role="presentation" set.

NVDA 2018.1 + Chrome latest

Navigating to a list NVDA will announce "list of # items" and then announce the first list item of the list, in the format of how NVDA announces individual listitem.

For role=list with listitem elements not set to display: list-item NVDA will announce the accessible name of each listitem.

If the listitem elements have display: list-item and a list-style: disc, NVDA will announce "bullet, accessible name" for each list item.

Chrome + NVDA have no issues announcing the number of items in a list, or navigating "grouped" lists regardless of role="presentation" being used or not.