Accessibility

Semantic markup, ARIA, and WCAG alignment for inclusive Chirp apps

2 min read 311 words

Overview

Chirp apps serve HTML over the wire. Following accessibility best practices ensures your app works for users of assistive technologies (screen readers, keyboard navigation) and benefits all users.

This guide covers patterns aligned with WCAG (Web Content Accessibility Guidelines). For comprehensive guidance, see the WAI-ARIA Authoring Practices and MDN Accessibility.

Semantic HTML

Use elements that convey meaning:

  • header, main, nav, footerfor page structure
  • article, sectionfor content grouping
  • h1h6for headings (in order, no skips)
  • button for actions, afor navigation
  • labelfor form controls
  • ul/ol/lifor lists
<header>
  <nav aria-label="Main navigation">...</nav>
</header>
<main>
  <article aria-label="Question and answer">
    <h2>Question</h2>
    <p>...</p>
  </article>
</main>

ARIA for Dynamic Content

When content updates via htmx or SSE, use ARIA to announce changes:

  • aria-live="polite"— announces updates without interrupting
  • aria-atomic="true"— reads the entire region when it changes
  • aria-label— describes regions and controls

The RAG demo uses this pattern for streaming answers:

<div sse-swap="answer" hx-target="this" aria-live="polite" aria-atomic="true">
  <span class="thinking">Searching docs and generating answer…</span>
</div>

Forms

  • Associatelabel with inputs via for/idor wrap the input
  • Usearia-describedbyfor validation messages
  • Usearia-invalidwhen a field has errors
  • Providearia-labelfor icon-only buttons
<label for="question-input">Your question</label>
<textarea id="question-input" name="question" aria-describedby="validation"></textarea>
<div id="validation" role="alert" aria-live="polite"></div>

Images and Media

  • Always providealt for images (empty string alt=""for decorative images)
  • Usetitle or aria-labelfor icon buttons

Keyboard and Focus

  • Ensure all interactive elements are focusable and operable via keyboard
  • Use visible focus styles (avoidoutline: nonewithout a replacement)
  • For custom controls (e.g. switches), userole="switch" and aria-checked

Next Steps