Who it affects
A student who is blind, checking the university library's opening hours hears seven lines of text with no list context, so cannot tell whether term-time and vacation hours are separate groups.
Someone who relies on a screen reader's list navigation (the L key in NVDA) finds nothing, because there is no list to find.
Someone using a reading tool that reformats the page sees the hours run together into one block.
Broken versus fixed
Both examples are live and rendered in a sandboxed frame. The broken one is deliberately broken.
Browsers draw the bullets anyway, so it looks fine. A screen reader announces the lines with no list, no count and no way to jump between them.
Announced: list, 3 items, then each item in turn. Only the wrapper changed.
Show the markup behind both examples
<style>body{font-family:system-ui;margin:0;padding:16px}.hours{margin:4px 0 0;padding-left:22px}li{margin:2px 0}</style>
<p style="margin:0"><strong>Main library, term time</strong></p>
<div class="hours">
<li>Monday to Friday, 8am to 10pm</li>
<li>Saturday, 9am to 6pm</li>
<li>Sunday, 11am to 6pm</li>
</div>
<style>body{font-family:system-ui;margin:0;padding:16px}.hours{margin:4px 0 0;padding-left:22px}li{margin:2px 0}</style>
<p style="margin:0"><strong>Main library, term time</strong></p>
<ul class="hours">
<li>Monday to Friday, 8am to 10pm</li>
<li>Saturday, 9am to 6pm</li>
<li>Sunday, 11am to 6pm</li>
</ul>
Test it by hand in two minutes
- Right click a bullet point, choose Inspect, and look at the parent of the li. It should be a ul or an ol, not a div or section.
- With NVDA running, press L to jump to the next list. If the bullets on screen are never reached, they are not a list.
- Open the component or template that outputs the items. The wrapper is often rendered in a different file, or only under some condition, and goes missing.
The fix
<div class="hours">
<li>Monday to Friday, 8am to 10pm</li>
<li>Saturday, 9am to 6pm</li>
</div>
<ul class="hours">
<li>Monday to Friday, 8am to 10pm</li>
<li>Saturday, 9am to 6pm</li>
</ul>
Change the wrapper, not the items. Use ol instead if the order carries meaning.
One line that is not a list
<section>
<li>Open now</li>
</section>
<section>
<p>Open now</p>
</section>
A single line on its own is not a list. Use a paragraph.
Items split across two wrappers
<div><li>Term time, 8am to 10pm</li></div>
<div><li>Vacation, 9am to 5pm</li></div>
<ul>
<li>Term time, 8am to 10pm</li>
<li>Vacation, 9am to 5pm</li>
</ul>
If the items belong together, put them in one list.
Common mistakes
- Adding role="list" to the div instead of using a ul, when a ul would do.
- Leaving the li where it is and hiding the bullets with CSS, hoping nobody notices.
- Using li as a generic row element in a grid or card layout.
- Putting li elements directly inside a nav element with no ul.
WCAG criteria this rule maps to
axe-core tags this rule as WCAG 2.2 level A. It is one of the checks for:
- 1.3.1 Info and Relationships (level A). Official W3C text.
The scanner can see an li whose parent is not a ul, ol or menu, or an element with role list. It cannot tell whether a set of lines that are not li elements at all should have been a list. Automated tools find only part of the accessibility problems on a page; a pass on this rule is not a pass on the criterion.
Related rules
list
A ul or ol tells a screen reader 'list, N items' and lets the person jump item by item.
A
Definition lists must be built from matching terms and descriptions
definition-list
A dl is a list of terms and their descriptions: each dt (the term) is followed by one or more dd (the description).
A
Terms and descriptions must sit inside a definition list
dlitem
dt and dd only mean term and description when they are inside a dl.