← Back

Demo 07: Lists & Groups

Semantic lists, card groups, and ARIA for collections

Structuring collections for screen readers

When you have multiple similar items (products, cards, list items), proper HTML structure helps users understand: how many items exist, which item they're on, and when they move to the next. Compare the examples below.

Tab Move between interactive elements ↑ ↓ Navigate list items (when applicable)

Lists: <ul>/<ol> vs <div>

BAD: Divs as List

Shopping Cart:

• iPhone 15 Pro $999
• AirPods Pro $249
• MagSafe Charger $39

What screen readers announce:

"Shopping Cart"

"bullet iPhone 15 Pro $999"

"bullet AirPods Pro $249"

"bullet MagSafe Charger $39"

⚠️ No list context! User doesn't know there are 3 items or their position.

</> For developers
<!-- BAD: Not a semantic list -->
<div>
  <div>Item 1</div>
  <div>Item 2</div>
  <div>Item 3</div>
</div>
Using divs loses all list semantics. Screen reader users can't tell how many items exist or where they are in the list.

GOOD: Semantic List

Shopping Cart:

  • iPhone 15 Pro $999
  • AirPods Pro $249
  • MagSafe Charger $39

What screen readers announce:

"Shopping Cart"

"list, Shopping cart items, 3 items"

"1 of 3, iPhone 15 Pro $999"

"2 of 3, AirPods Pro $249"

"3 of 3, MagSafe Charger $39"

✓ Full context! User knows total count and current position.

</> For developers
<!-- GOOD: Semantic list -->
<ul aria-label="Shopping cart">
  <li>iPhone - $999</li>
  <li>AirPods - $249</li>
  <li>Charger - $39</li>
</ul>
Semantic <ul>/<li> gives full context. Add aria-label to describe what the list contains.

Card Groups: article vs div

BAD: Div Cards

Product A
$49.99
Add
Product B
$79.99
Add

Accessibility tree:

generic
├─ generic
│  ├─ img (no alt!)
│  ├─ generic "Product A"
│  ├─ generic "$49.99"
│  └─ generic "Add"
├─ generic
│  └─ ...same mess...

⚠️ No structure! Everything is "generic".

</> For developers
<!-- BAD: No semantic structure -->
<div class="card">
  <img src="...">
  <div>Product A</div>
  <div onclick="add()">Add</div>
</div>
Divs everywhere = no structure. Screen readers can't tell where one card ends and another begins.

GOOD: Article Cards

  • Product A thumbnail

    Product A

    $49.99

  • Product B thumbnail

    Product B

    $79.99

Accessibility tree:

list "Product listing" (2 items)
├─ listitem (1 of 2)
│  └─ article
│     ├─ img "Product A thumbnail"
│     ├─ heading "Product A"
│     ├─ text "$49.99"
│     └─ button "Add to cart"
├─ listitem (2 of 2)
│  └─ article
│     └─ ...

✓ Clear structure! Each card is an article inside a list.

</> For developers
<!-- GOOD: Semantic card structure -->
<ul role="list" aria-label="Products">
  <li>
    <article>
      <img src="..." alt="Product A">
      <h4>Product A</h4>
      <button>Add to cart</button>
    </article>
  </li>
</ul>
Wrap cards in <ul><li> for list semantics. Use <article> for self-contained content.

Navigation Groups with ARIA

Tab Navigation Example

Use arrow keys to navigate between tabs:

This is the product description panel. Full details about the product go here.

</> For developers
<div role="tablist">
  <button role="tab" aria-selected="true">
    Tab 1
  </button>
  <button role="tab" aria-selected="false">
    Tab 2
  </button>
</div>

<div role="tabpanel">
  Content here
</div>
Tab interfaces need role="tablist", role="tab", role="tabpanel". Use arrow keys to navigate, Tab to enter/exit the group.
ARIA Landmark Regions
Use role="region" with aria-label to create named sections. Screen readers can jump between regions with shortcuts.

What Screen Readers Announce

❌ Without Semantics

Screen reader says:
→ "text, text, text..."
→ no item count
→ no position info
User has no context!

✅ With Semantics

Screen reader says:
"list, 3 items"
→ "1 of 3: iPhone Pro"
→ "2 of 3: AirPods"
→ "3 of 3: Charger"
Full context!