ul and ol with children that are not list items
A div between the li elements of a list changes what a screen reader announces. squirrel checks the direct children of every list.
What list structure is
A screen reader announces a list by its item count: “list, 6 items”. That count comes from the direct children of the <ul> or <ol>, so anything else sitting at that level either breaks the count or breaks the list entirely.
HTML allows <li> and script-supporting elements as the children of a <ul> or <ol>, and nothing else. squirrel additionally accepts an element carrying role="listitem", which restores the semantics for markup that cannot use the tag even though it is not conforming HTML. Either way, wrappers added for styling belong inside the <li>, not around it.
What squirrel checks
One check, list-structure, at severity error. It reads the direct children of every <ul> and <ol>.
- Fail when a direct child is anything other than
<li>, an element withrole="listitem",<script>or<template>. Report message:N list(s) with invalid child elements. Each list is namedul#nav,ol.stepsor a bare tag, up to ten with a count of the rest. - Pass with
N list(s) are properly structured. - Info with
No ul/ol lists found.
<script> and <template> are allowed, matching HTML’s rule that script-supporting elements may appear between list items. The check reports the list rather than the offending child, and stops at the first bad child in each list.
How to fix it
<ul>
<li>
<div class="card">
<h3>Team</h3>
</div>
</li>
</ul>Move the wrapper inside the <li>. If the container is a grid or a flex layout, put the display property on the <ul> and let the <li> elements be the grid items.
Where the markup genuinely cannot use <li>, role="list" on the container and role="listitem" on each child restores the semantics. Both halves are needed: one without the other leaves the list broken in a different way.
| Rule ID | a11y/list-structure |
| Category | Accessibility |
| Scope | Per-page |
| Severity | error |
| Weight | 7/10 |
Enable / disable
Disable this rule
[rules]
disable = ["a11y/list-structure"]Disable all Accessibility rules
[rules]
disable = ["a11y/*"]Enable only this rule
[rules]
enable = ["a11y/list-structure"]enable replaces the default ["*"], so this is the only rule selected. Leave disable out: a rule that matches any disable pattern is skipped even when enable names it. Only an enabled setting under a rule’s own [rule_options] table overrides both lists.
Related rules
- a11y/listitem:
<li>elements whose parent is not a list. - a11y/definition-list: the same check for
<dl>. - a11y/aria-required-children:
role="list"with no items inside it. - a11y/aria-required-parent: the same relationship seen from the item.
Accessibility findings ship in every audit next to the SEO, performance and agent experience rules. See Website security scan with AI for how an agent works through a report.
References
Check your site
Run squirrel audit https://example.com and open the Accessibility section of the report. Each malformed list is listed by id or class. Signed-out local audits need no account and cost nothing. Signed-in audits spend credits.