Accessibilitymediumdocument-structure
Use semantic list elements
rule · semantic-lists
Semantic list elements tell screen readers the content structure, enabling efficient navigation.
Code Example
HTML
<!-- ❌ Bad: Styled divs with no semantics -->
<div class="feature-list">
<div class="feature">Fast performance</div>
<div class="feature">Easy setup</div>
<div class="feature">24/7 support</div>
</div>
<!-- ✅ Good: Semantic unordered list -->
<ul class="feature-list">
<li>Fast performance</li>
<li>Easy setup</li>
<li>24/7 support</li>
</ul>Why It Matters
Screen readers announce list structure and item count—'list with 5 items'—helping users understand content organization. Styled divs provide no context.
List Types
| Element | Use For | Announcement |
|---|---|---|
<ul> | Unordered items | "List with X items" |
<ol> | Ordered sequences | "List with X items" + position |
<dl> | Term-definition pairs | "Definition list" |
Ordered Lists
HTML
<!-- ❌ Bad: Manual numbering -->
<div class="steps">
<div>1. Sign up for an account</div>
<div>2. Complete your profile</div>
<div>3. Start using the app</div>
</div>
<!-- ✅ Good: Semantic ordered list -->
<ol class="steps">
<li>Sign up for an account</li>
<li>Complete your profile</li>
<li>Start using the app</li>
</ol>Definition Lists
HTML
<!-- ✅ Good: Term-definition pairs -->
<dl class="glossary">
<dt>API</dt>
<dd>Application Programming Interface</dd>
<dt>REST</dt>
<dd>Representational State Transfer</dd>
<dt>JSON</dt>
<dd>JavaScript Object Notation</dd>
</dl>
<!-- FAQ using definition list -->
<dl class="faq">
<dt>How do I reset my password?</dt>
<dd>Click the "Forgot Password" link on the login page.</dd>
<dt>What payment methods do you accept?</dt>
<dd>We accept Visa, Mastercard, and PayPal.</dd>
</dl>Navigation Lists
HTML
<!-- ✅ Good: Navigation as list -->
<nav aria-label="Main navigation">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/products">Products</a></li>
<li><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
</nav>React Component
TSX
interface ListProps {
items: string[]
ordered?: boolean
}
function List({ items, ordered = false }: ListProps) {
const Tag = ordered ? 'ol' : 'ul'
return (
<Tag>
{items.map((item, index) => (
<li key={index}>{item}</li>
))}
</Tag>
)
}CSS Styling
CSS
/* Remove default bullets while keeping semantics */
ul.clean-list {
list-style: none;
padding: 0;
margin: 0;
}
/* Custom bullets with accessibility preserved */
ul.custom-bullets li::before {
content: "✓";
margin-right: 0.5em;
color: green;
}Exceptions
- Evaluate the rendered experience before treating a static-code smell as a blocker; interaction timing, browser behavior, and assistive technology output often determine severity.
- Not every secondary accessibility issue deserves equal weight; prioritize the issue that most directly blocks perception, operation, or understanding.
- Avoid adding redundant markup or ARIA solely to satisfy a rule when a simpler semantic implementation would eliminate the issue entirely.
Verification
Automated Checks
- Use browser accessibility tooling, axe, Lighthouse, or equivalent automated checks against a representative rendered state.
Manual Checks
- Use screen reader to navigate lists
- Verify "list with X items" announcement
- Check item count matches visible items