ADR-018: Contact Page Accessibility Enhancements
Status
Section titled “Status”Accepted
Note: This ADR documents the implementation of patterns defined in ADR 019: Accessibility Patterns & Standards. Refer to ADR 019 for comprehensive accessibility guidelines.
Context
Section titled “Context”The contact.astro page contained several accessibility issues that could impact screen reader users:
- Decorative emojis were not hidden from assistive technology, causing redundant announcements
- Badge components used
role="status"for all instances, even when decorative or informational - Focus order in grid layouts needed validation documentation
These issues violated WCAG 2.1 Level AA guidelines for perceivable and operable content.
Decision
Section titled “Decision”Amendment (2026-08-02): the contact page no longer contains these emojis or any
role="status"badge — the emoji icons were replaced by theIconatom, whosedecorativeprop appliesaria-hiddeninternally (ADR-055), and the remaining badges all userole="presentation". The patterns below are preserved as the decision record.
We will implement the following accessibility enhancements:
1. Decorative Emojis with aria-hidden="true"
Section titled “1. Decorative Emojis with aria-hidden="true"”All decorative emojis that serve purely visual purposes will be hidden from screen readers:
<!-- Before --><span class="text-2xl">📧</span>
<!-- After --><span class="text-2xl" aria-hidden="true">📧</span>Affected emojis (9 total):
- 📧 Email icon
- 💬 Chat icon
- 📞 Phone icon
- 📍 Location icon
- 🕒 Time icon
- 🌍 Globe icon
- ⚡ Lightning icon
- 🎯 Target icon
- 🤝 Handshake icon
Rationale: Adjacent text already conveys the meaning (e.g., “Email” heading next to 📧), making emoji announcement redundant and potentially confusing.
2. Semantic Badge Roles
Section titled “2. Semantic Badge Roles”Badge components now use appropriate ARIA roles based on their purpose:
<!-- Decorative/Informational badges --><Badge role="presentation">Available for new projects</Badge><Badge role="presentation">Remote-friendly</Badge>
<!-- Status badges (live updates) --><Badge role="status">Online now</Badge>Role Guidelines:
role="presentation"- Decorative or informational badges that don’t announce status changesrole="status"- Live status updates that should be announced (e.g., “Online now”)- No role - Default for general informational content
3. Focus Order Documentation
Section titled “3. Focus Order Documentation”Added HTML comments documenting that grid layouts follow natural DOM order for keyboard navigation:
<!-- Focus order: Grid flows naturally left-to-right, top-to-bottom for keyboard navigation --><section class="py-16 bg-background-surface"> <div class="grid md:grid-cols-3 gap-8"> <!-- Content flows naturally --> </div></section>Consequences
Section titled “Consequences”Positive
Section titled “Positive”- Screen Reader Experience: Eliminates redundant emoji announcements, reducing cognitive load
- Semantic Correctness: Badge roles accurately reflect their purpose
- WCAG AA Compliance: Meets WCAG 2.1 Level AA criteria for:
- 1.1.1 Non-text Content (Level A)
- 1.3.1 Info and Relationships (Level A)
- 2.4.3 Focus Order (Level A)
- Developer Clarity: Comments document accessibility considerations for future maintainers
- Testing Ready: Changes enable proper automated accessibility testing
Negative
Section titled “Negative”- Minimal: No negative consequences - these are pure accessibility improvements
Neutral
Section titled “Neutral”- Visual Appearance: No visual changes - only affects assistive technology
- Performance: No performance impact
Implementation Details
Section titled “Implementation Details”Emoji Accessibility Pattern
Section titled “Emoji Accessibility Pattern”<!-- Decorative emoji (visual enhancement only) --><span aria-hidden="true">📧</span><h3>Email</h3> <!-- Text conveys meaning -->
<!-- Meaningful emoji (rare - would need alt text via title or aria-label) --><span role="img" aria-label="Warning">⚠️</span>Badge Role Decision Tree
Section titled “Badge Role Decision Tree”Is the badge announcing a live status change?├─ YES → role="status" (e.g., "Online now", "Processing")└─ NO → Is it purely decorative? ├─ YES → role="presentation" └─ NO → No role (default semantic span)Testing Recommendations
Section titled “Testing Recommendations”-
Screen Reader Testing:
- NVDA (Windows)
- JAWS (Windows)
- VoiceOver (macOS/iOS)
-
Keyboard Navigation:
- Tab through all interactive elements
- Verify focus order is logical (left-to-right, top-to-bottom)
- Ensure no keyboard traps
-
Automated Testing:
Terminal window pnpm run test:a11y # Playwright with axe-core
Related ADRs
Section titled “Related ADRs”- ADR 000: Starter Decisions - WCAG AA compliance requirement
- ADR 003: Unified Component Structure - Atomic design pattern (the planned “ADR-016: Badge Component” was never written; see the 016 stub)
- ADR 019: Accessibility Patterns & Standards - Consolidated accessibility guidelines
References
Section titled “References”Enforcement
Section titled “Enforcement”- Testable consequences:
- TC-1: the contact page passes the automated axe sweep in the E2E suite (
e2e/a11y-axe.spec.ts, wired 2026-08-13 — the claim predated the integration).
- TC-1: the contact page passes the automated axe sweep in the E2E suite (
- Checks:
- TC-1 →
@a11yPlaywright suite in CI (status: block, pre-existing gate)
- TC-1 →
- Not machine-checkable: whether a given emoji is decorative or meaningful is a content judgment.
- Graduation log: (empty at creation; entries added when a check changes status)
Date: 2025-10-01 (footer backfilled 2026-07-05 from git history; this record predates the footer convention)
Participants: Template maintainers
Outcome: Accepted