ACCESSIBILITY ENGINEERING MASTERY
In the early web, accessibility was an afterthought—a few `alt` attributes on images. Today, accessibility (a11y) is a core engineering discipline. It is the study of how information is structured so that it can be consumed by *any* user agent, regardless of sensory or motor capability.
Learn Accessibility Engineering: From Zero to AOM Master
Goal: Deeply understand how the web is perceived by non-visual agents—mastering the transformation from raw HTML to the Accessibility Object Model (AOM), implementing the “AccName” calculation algorithm, and building tools that bridge the gap between pixels and semantic meaning. You will move beyond “alt tags” to understanding the deep architecture of Assistive Technology (AT) integration.
Why Accessibility Engineering Matters
In the early web, accessibility was an afterthought—a few alt attributes on images. Today, accessibility (a11y) is a core engineering discipline. It is the study of how information is structured so that it can be consumed by any user agent, regardless of sensory or motor capability.
The Current State of Web Accessibility (2024-2025)
The numbers tell a sobering story:
- 94.8% of home pages had detectable WCAG 2 failures in 2025 (only a slight improvement from 95.9% in 2024)
- 51 errors per page on average across one million websites
- 79.1% of sites have low contrast text issues
- 18.5% of images are missing alternative text
- Yet 72% of organizations now have accessibility policies and 85% see it as a competitive advantage
Despite growing awareness, actual WCAG compliance remains critically low. This creates massive opportunity for engineers who truly understand accessibility implementation.
Why This Matters
-
The Semantic Bridge: Browsers don’t just “render” HTML; they translate it into a second, invisible tree structure called the Accessibility Tree. This is what screen readers like NVDA, JAWS, and VoiceOver actually “read.”
-
Legal & Ethical Imperative: In many jurisdictions (ADA in US, EAA in Europe), digital accessibility is a legal requirement. A 2024 UK report found 68% of public sector sites achieved partial or full compliance—private sector lags far behind.
-
The “Curb Cut” Effect: Designing for accessibility improves the experience for everyone (e.g., captions used by people in loud rooms, or high contrast used by people in bright sunlight).
-
Machine Understanding: An accessible site is a machine-readable site. Accessibility engineering is the precursor to how LLMs and AI agents will navigate the web.
-
Market Reality: Over 1 billion people worldwide have disabilities. Ignoring accessibility means excluding 15% of potential users.
Prerequisites & Background Knowledge
Essential Prerequisites (Must Have)
Before diving into accessibility engineering, you should have:
- HTML/CSS Fundamentals
- Understand semantic HTML elements (
<nav>,<main>,<button>,<header>) - Know how the DOM tree is constructed from HTML
- Basic CSS selectors and display properties
- Understand semantic HTML elements (
- JavaScript Basics
- DOM manipulation (querySelector, createElement, appendChild)
- Event listeners (click, keypress, focus, blur)
- Asynchronous programming (Promises, async/await)
- Developer Tools Proficiency
- Chrome/Firefox DevTools for inspecting elements
- Understanding of browser console and debugging
- Programming Fundamentals
- Tree data structures and recursive traversal
- String manipulation and parsing
- Object-oriented or functional programming patterns
Helpful But Not Required
These will be learned during the projects:
- Screen reader experience - You’ll build one, so prior use is optional
- WCAG specification knowledge - Projects will introduce this incrementally
- Browser rendering internals - Concepts covered in detail
- Platform accessibility APIs - Advanced topic for later projects
Self-Assessment Questions
Can you answer these? If not, review before starting:
- What is the difference between
<div>and<section>in terms of semantics? - How do you select all children of a DOM node in JavaScript?
- What does “recursion” mean and when would you use it?
- What is the difference between
display: noneandvisibility: hidden? - How do event listeners work in JavaScript?
- What is a tree data structure?
If you answered “no” to more than 2 questions, spend a weekend reviewing:
- “Eloquent JavaScript” Ch. 13-14 (DOM) and Ch. 13 (Data Structures)
- MDN HTML Semantics Guide (online)
Development Environment Setup
Required Tools:
- Node.js (v18+) or Python (3.10+) - for building parsers
- Code editor - VS Code recommended (has good accessibility inspection tools)
- Browser - Chrome or Firefox (both have excellent Accessibility DevTools)
- Screen reader (optional but recommended):
- macOS: VoiceOver (built-in, Cmd+F5 to enable)
- Windows: NVDA (free download)
- Linux: Orca (usually pre-installed)
Recommended Tools:
- Playwright or Puppeteer - for browser automation (Projects 4, 9)
- TypeScript - strongly typed environment helps with complex tree structures
- axe-core - for comparing your results to industry tools (validation)
Time Investment
Be realistic about the time commitment:
| Experience Level | Weekly Hours | Total Duration |
|---|---|---|
| Beginner (learning HTML/JS too) | 8-10 hours | 3-4 months |
| Intermediate (know web dev) | 5-7 hours | 6-8 weeks |
| Advanced (systems background) | 3-5 hours | 4-6 weeks |
Per-project estimates:
- Simple projects (1, 5): 1-2 weekend days
- Medium projects (2, 4, 7, 8, 10): 4-7 days
- Complex projects (3, 6, 9): 10-14 days
Important Reality Check
This is not a “learn accessibility guidelines” course. This is accessibility engineering—you will:
- ✅ Implement the W3C AccName specification from scratch
- ✅ Build parsers that walk DOM trees
- ✅ Write algorithms that browsers use internally
- ✅ Create developer tools that expose hidden structures
This is not:
- ❌ A WCAG compliance checklist course
- ❌ A “how to write good alt text” guide
- ❌ A UI/UX accessibility patterns workshop
If you want to use accessibility features correctly, read the W3C WAI-ARIA Authoring Practices. This course teaches you how those features work under the hood.
Core Concept Analysis
1. The Multi-Tree Architecture
A browser manages at least three distinct representations of a single web page. Understanding the “handshake” between these trees is the essence of a11y engineering.
[ HTML Source ]
│
▼
[ DOM Tree ] (Document Object Model)
│
├─────────────────────────┐
│ ▼
│ [ CSSOM Tree ] (CSS Object Model)
│ │
└──────────┬──────────────┘
▼
[ Layout Tree ] (Visual rendering)
│
▼
[ Accessibility Tree ] (Semantic Model)
│
▼
[ Platform Accessibility API ] (UI Automation, AT-SPI, IAccessible2)
│
▼
[ Assistive Technology ] (Screen Reader, Braille Display, Switch)
2. The Four Pillars of the Accessibility Tree
Every node in the Accessibility Tree has four primary characteristics:
- Role: What is it? (e.g.,
button,link,heading) - Name: What is its label? (e.g., “Submit”, “Home”)
- State: What is it doing? (e.g.,
focused,expanded,collapsed) - Value: What data does it hold? (e.g., “50%” for a progress bar)
3. ARIA (Accessible Rich Internet Applications)
When semantic HTML (<button>, <nav>) isn’t enough, ARIA provides a way to “patch” the Accessibility Tree.
DOM: <div onclick="submit()">Submit</div>
A-Tree: [Static Text: "Submit"] (Screen reader: "Submit")
-- vs --
DOM: <div role="button" onclick="submit()">Submit</div>
A-Tree: [Button: "Submit"] (Screen reader: "Submit, Button")
The “AccName” Algorithm: The Hardest Part
The “Accessible Name and Description Computation” spec is a 14-step recursive algorithm. It determines exactly what a screen reader says for a given element. It looks at aria-labelledby, then aria-label, then alt attributes, then the element’s actual text content.
[ Element: <img src="dog.jpg" alt="A golden retriever"> ]
│
└─ Calculation:
1. Is aria-labelledby present? No.
2. Is aria-label present? No.
3. Is it an <img>? Yes.
4. Does it have an alt? Yes.
5. Name = "A golden retriever"
Concept Summary Table
| Concept Cluster | What You Need to Internalize |
|---|---|
| The A-Tree | The filtered version of the DOM sent to the OS. Not everything in DOM is in A-Tree (e.g., aria-hidden="true"). |
| Semantic HTML | The built-in mapping of tags (e.g., <header>) to roles (landmark). Use native elements whenever possible. |
| AccName Spec | The complex hierarchy of how an element’s text label is derived from its attributes and children. |
| Focus Management | How the “active” element moves. Keyboard navigation is the primary driver of the A-Tree experience. |
| WAI-ARIA | A set of attributes to describe complex widgets (tabs, accordions) that have no native HTML equivalent. |
Deep Dive Reading by Concept
Foundation
| Concept | Book & Chapter |
|---|---|
| Core Accessibility Principles | “Inclusive Design Patterns” by Heydon Pickering — Ch. 1: “The Core Principles” |
| Semantic HTML Basics | “Accessibility for Everyone” by Laura Kalbag — Ch. 3: “Content and Structure” |
Advanced Implementation
| Concept | Book & Chapter |
|---|---|
| WAI-ARIA Patterns | “W3C WAI-ARIA Authoring Practices“ (Online Spec) — “Design Patterns and Widgets” |
| The AccName Algorithm | “Accessible Name and Description Computation 1.2” (W3C Specification) |
| Browser Accessibility Implementation | “Full Accessibility Tree in Chrome DevTools“ — Chrome Developers Blog |
| Firefox Accessibility Tree | “How Accessibility Trees Inform Assistive Tech“ — Mozilla Hacks |
Essential Reading Order
For maximum comprehension, follow this sequence:
- Week 1 - Foundations:
- “Accessibility for Everyone” Ch. 3 (Content and Structure)
- “Inclusive Design Patterns” Ch. 1 (Core Principles)
- MDN Accessibility Tree Glossary
- Week 2-3 - Tree Implementation:
- “Eloquent JavaScript” Ch. 13 (DOM)
- W3C HTML-ARIA Mapping Spec (scan implicit roles)
- Build Projects 1-2
- Week 4-6 - ARIA and AccName:
- W3C WAI-ARIA Authoring Practices (patterns you’re implementing)
- AccName Specification (recursive algorithm)
- Build Projects 2-3
- Week 7+ - Advanced Topics:
- WCAG 2.1 (specific success criteria as needed)
- Browser DevTools documentation for verification
- Build Projects 4-10
Quick Start Guide (For the Overwhelmed)
Feeling lost? Start here.
Your First 48 Hours
Day 1: See the Invisible Tree
- Enable Accessibility Inspector (15 min)
- Chrome: DevTools → Elements → Accessibility pane
- Firefox: DevTools → Accessibility tab
- Open any website and explore the tree
- Build Mini-Project 1 (3-4 hours)
- Use Cheerio (Node) or BeautifulSoup (Python)
- Parse
<nav>,<button>,<a>tags - Print their implicit roles
- Success criteria: See “navigation”, “button”, “link” in output
- Test with Real Screen Reader (30 min)
- Enable VoiceOver/NVDA
- Navigate with Tab key only
- Notice what gets announced vs what’s silent
Day 2: Break Something and Fix It
- Create a Broken Page (1 hour)
- Build an HTML page with:
<div onclick="...">Submit</div>(fake button)<img src="...">(no alt text)<div role="navigation">(should be<nav>)
- Build an HTML page with:
- Run Your Tool (1 hour)
- Process your broken page
- Compare output to browser’s Accessibility Tree
- Goal: Understand why
<div>isn’t focusable
- Read One Core Resource (2 hours)
- Common ARIA Mistakes
- Take notes on what you learned
End of 48 Hours: You should understand:
- The Accessibility Tree is separate from the DOM
- Semantic HTML creates implicit roles
<div>tags are invisible to assistive technology- ARIA can override (and break) semantics
Next Step: Build Project 1 properly, then move to Project 2.
Recommended Learning Paths
Path 1: The Web Developer (Building Better UIs)
Background: You build React/Vue apps and want to make them accessible.
Your Journey:
- Week 1-2: Projects 1, 2 (understand the tree and ARIA)
- Week 3: Project 5 (contrast ratios for design systems)
- Week 4-5: Project 4 (keyboard navigation patterns)
- Week 6: Project 7 (handling SPA mutations)
- Week 7+: Project 10 (AI-assisted content auditing)
Why this path: Focuses on practical tools you’ll use daily in component development.
Path 2: The Systems Engineer (Understanding Browser Internals)
Background: You’re comfortable with C/C++, want to understand how browsers implement accessibility.
Your Journey:
- Week 1: Project 1 (semantic mapping)
- Week 2-3: Project 3 (AccName algorithm—the hardest)
- Week 4: Project 6 (build a screen reader from scratch)
- Week 5: Project 7 (MutationObserver and tree diffs)
- Week 6: Project 9 (spatial focus mapping)
- Week 7+: Final Project (full AOM auditor)
Why this path: Deep-dives into algorithms and tree operations browsers use internally.
Path 3: The Accessibility Auditor (Professional Testing)
Background: You audit sites for WCAG compliance and want to build custom tools.
Your Journey:
- Week 1: Project 1 (foundation)
- Week 2: Project 4 (keyboard trap detection—common issue)
- Week 3: Project 5 (contrast calculation—most frequent error)
- Week 4-5: Project 3 (AccName for accurate testing)
- Week 6: Project 8 (complex table structures)
- Week 7+: Project 10 (automated alt text evaluation)
- Week 8+: Final Project (comprehensive auditing suite)
Why this path: Covers the top 5 WCAG failure points with custom tooling.
Path 4: The Curious Beginner (Learning from Zero)
Background: New to accessibility, want to understand it properly.
Your Journey:
- Week 1: Read “Accessibility for Everyone” Ch. 1-3
- Week 2: Project 1 (see the tree structure)
- Week 3: Use a screen reader for a full day (experience over theory)
- Week 4: Project 5 (understand contrast math)
- Week 5-6: Project 2 (learn ARIA properly)
- Week 7: Project 4 (keyboard accessibility)
- Week 8+: Choose advanced projects based on interest
Why this path: Balances theory, experience, and hands-on building with gentler slope.
Project List
Projects are ordered from fundamental parsing to complex behavioral simulations.
Project 1: The Semantic Tag Mapper (A-Tree Foundation)
- File: ACCESSIBILITY_ENGINEERING_MASTERY.md
- Main Programming Language: TypeScript
- Alternative Programming Languages: Python, Rust, Go
- Coolness Level: Level 3: Genuinely Clever
- Business Potential: 1. The “Resume Gold”
- Difficulty: Level 1: Beginner
- Knowledge Area: HTML Parsing / DOM Mapping
- Software or Tool: JSDOM or Cheerio
- Main Book: “Accessibility for Everyone” by Laura Kalbag
What you’ll build: A tool that takes an HTML string and produces a simplified tree structure where every node is replaced by its “Implicit Role” (e.g., <a> becomes link, <h1> becomes heading).
Why it teaches a11y: This project forces you to realize that the browser ignores the “tag name” and looks for the “semantic meaning.” You’ll learn the mapping of standard HTML5 elements to their default roles in the Accessibility Tree.
Core challenges you’ll face:
- Implicit Role Mapping → maps to understanding that <nav> is a “navigation” landmark
- Filtering non-semantic elements → maps to *realizing <div> and are invisible to the A-Tree by default*
- Recursive Tree Traversal → maps to walking the DOM to build the A-Tree
Key Concepts:
- Implicit Roles: W3C HTML-ARIA Mapping Spec
- Tree Traversal: “Eloquent JavaScript” Ch. 13 - Marijn Haverbeke
Difficulty: Beginner Time estimate: Weekend Prerequisites: Basic knowledge of HTML and recursion in your chosen language.
Real World Outcome
You’ll have a CLI tool that “audits” a page’s structure. Instead of seeing a mess of divs, you’ll see the page the way a screen reader does.
Example Output:
$ node map_tree.js index.html
[Root: "Document"]
├── [Landmark: "banner"]
│ └── [Heading Level 1: "Acme Corp"]
├── [Landmark: "main"]
│ ├── [Section: "About Us"]
│ └── [Link: "Read More"]
└── [Landmark: "contentinfo"]
└── [Text: "Copyright 2025"]
The Core Question You’re Answering
“If I removed all the visual styling and tags, what is the structure of the information remaining?”
Before you write any code, sit with this question. A screen reader doesn’t care if a button is blue or has a rounded corner. It only cares that it is a button.
Concepts You Must Understand First
Stop and research these before coding:
- The DOM Tree
- What is the difference between an Element and a Node?
- How do children inherit properties?
- Book Reference: “Eloquent JavaScript” Ch. 13
- Implicit Roles
- What role does a
<form>have? (Hint: it’s not always ‘form’) - Why do
<div>tags disappear in the Accessibility Tree? - Resource: MDN “ARIA Roles” documentation
- What role does a
Questions to Guide Your Design
Before implementing, think through these:
- Mapping Logic
- Will you use a large
switchstatement or a lookup table for tag-to-role mapping? - How will you handle heading levels (h1-h6)?
- Will you use a large
- Node Filtering
- If a
<div>contains a<button>, should the<div>show up in your tree? Why or why not?
- If a
Thinking Exercise
The Semantic X-Ray
Look at this snippet:
<section>
<div class="header">
<h1>Our Team</h1>
</div>
<div class="content">
<p>We are experts.</p>
</div>
</section>
Questions while tracing:
- Which elements here contribute to the A-Tree?
- Does the
.headerdiv add any value to a blind user? - What is the role of the
<section>tag?
The Interview Questions They’ll Ask
Prepare to answer these:
- “What is the ‘Implicit Role’ of a
<button>tag?” - “Why is it better to use
<nav>instead of<div role='navigation'>?” - “How does the browser decide which DOM nodes to include in the Accessibility Tree?”
- “What is a ‘Landmark’ in accessibility terms?”
- “Can a
<div>ever have a role?”
Hints in Layers
Hint 1: The Setup
Use a library like Cheerio (Node) or BeautifulSoup (Python) to parse the HTML so you can focus on the mapping logic, not the regex.
Hint 2: The Mapping
Create a JSON file that maps tags to roles. Start with: a: link, button: button, h1: heading, ul: list.
Hint 3: Handling Recursion
Write a function processNode(node). If the node has an implicit role, add it to your result tree. Then, call processNode on all of its children.
Hint 4: Pretty Printing Use the “indentation” trick (adding 2 spaces per level of depth) to make your output look like a tree in the console.
Books That Will Help (Project 1)
| Topic | Book | Chapter |
|---|---|---|
| DOM Tree Traversal | “Eloquent JavaScript” by Marijn Haverbeke | Ch. 13: “JavaScript and the Browser” |
| Recursive Algorithms | “Grokking Algorithms” by Aditya Bhargava | Ch. 3: “Recursion” |
| Semantic HTML | “Accessibility for Everyone” by Laura Kalbag | Ch. 3: “Content and Structure” |
Common Pitfalls & Debugging (Project 1)
Problem 1: “My tool shows <div> tags in the tree”
- Why: You’re including all DOM nodes instead of filtering by semantic meaning
- Fix: Check if the element has an implicit role.
<div>and<span>have no implicit role unlessrole=attribute is present - Quick test:
node map_tree.json a page with many divs—output should be sparse
Problem 2: “Headings don’t show their level (h1, h2, etc.)”
- Why: You’re mapping all headings to just “heading” instead of “heading level 1”, “heading level 2”
- Fix: Extract the tag name’s number:
tagName.match(/h(\d)/)[1] - Quick test: Parse a page with h1-h6, verify each shows its level
Problem 3: “The tree structure looks flat, not nested”
- Why: You’re not recursing into children, or your indentation logic is wrong
- Fix: For each child, call your function recursively with
depth + 1 - Quick test: Parse a page with nested
<nav><ul><li>structure—should show 3 levels
Problem 4: “Tool crashes on real-world pages”
- Why: You’re not handling edge cases like text nodes, comments, or malformed HTML
- Fix: Add type checks:
if (node.nodeType !== 1) continue;(1 = element node) - Quick test: Parse a page with HTML comments—should ignore them
Learning Milestones (Project 1)
-
Milestone 1: The “Aha” Moment → You see a complex page reduced to just its semantic bones. You realize most of the HTML is visual scaffolding.
-
Milestone 2: Implicit Role Mastery → You can look at any HTML tag and instantly know its role without checking documentation.
-
Milestone 3: Tree Thinking → You start seeing web pages as trees, not flat documents. You understand why recursion is natural for DOM processing.
Project 2: The ARIA Resolver (State and Role Override)
- File: ACCESSIBILITY_ENGINEERING_MASTERY.md
- Main Programming Language: TypeScript
- Alternative Programming Languages: Rust, Python
- Coolness Level: Level 3: Genuinely Clever
- Business Potential: 1. The “Resume Gold”
- Difficulty: Level 2: Intermediate
- Knowledge Area: ARIA Implementation
- Software or Tool: Custom Parser
- Main Book: “Inclusive Design Patterns” by Heydon Pickering
What you’ll build: An extension of Project 1 that correctly handles role="...", aria-hidden, and state attributes like aria-expanded.
Why it teaches a11y: You will learn how ARIA attributes override the native semantics of the DOM. You’ll understand why aria-hidden="true" is a “nuclear option” for the Accessibility Tree.
Core challenges you’ll face:
- Role Overriding → maps to realizing that <div role="button"> must be treated as a button
- Hidden Subtrees → maps to pruning the tree when aria-hidden is encountered
- State Capture → maps to extracting ‘expanded’ vs ‘collapsed’ information
Key Concepts:
- ARIA Override: W3C ARIA Spec Section 3.2.2
- Accessibility Pruning: How browsers remove nodes from the tree
Difficulty: Intermediate Time estimate: 1 week Prerequisites: Completion of Project 1, understanding of HTML attributes, basic knowledge of CSS selectors for hidden elements.
Real World Outcome
A tool that detects “Semantics Lying.” If a developer puts role="link" on a button, your tool will report the final calculated role.
Example Output:
$ ./resolve_aria "<div role='button' aria-expanded='true'>Click Me</div>"
Calculated Role: button
Calculated State: expanded=true
Calculated Name: "Click Me"
$ ./resolve_aria "<button role='link'>Submit Form</button>"
⚠ Warning: Role override detected!
Native Role: button
Override Role: link
Calculated Name: "Submit Form"
⚠ This element will be announced as a link but behaves as a button!
$ ./resolve_aria "<nav aria-hidden='true'><a href='/home'>Home</a></nav>"
Calculated Role: navigation
Calculated State: hidden=true
⚠ This entire subtree is hidden from assistive technology!
You’ll see exactly how ARIA attributes override native semantics and when developers are creating accessibility anti-patterns.
The Core Question You’re Answering (Project 2)
“How do I make a generic
<div>act like a complex widget without writing a whole browser engine?”
ARIA is a “promise” you make to the browser. This project teaches you exactly which promises the A-Tree trusts and which ones it ignores. You’ll learn the critical difference between:
- Implicit semantics (from HTML tags)
- Explicit semantics (from ARIA attributes)
- When ARIA helps vs when ARIA breaks accessibility
Concepts You Must Understand First (Project 2)
Stop and research these before coding:
- ARIA Role Override
- Can any element have any role? (No! Some roles are forbidden on certain elements)
- What happens when you put
role="button"on an<a>tag? - Does
roleaffect the element’s behavior, or just its announcement? - Book Reference: W3C ARIA Specification Section 3.2.2 “Implicit vs Explicit Roles”
- State vs Property
- What’s the difference between
aria-expandedandaria-describedby? - Which ARIA attributes are “states” (change during interaction) vs “properties” (rarely change)?
- Resource: WAI-ARIA Authoring Practices - “States and Properties”
- What’s the difference between
- The
aria-hiddenNuclear Option- When you set
aria-hidden="true", what happens to child elements? - Can you make a focusable element hidden from screen readers? (Yes, and it’s a bug!)
- Resource: Common ARIA Mistakes - “aria-hidden on focusable elements”
- When you set
- CSS vs ARIA Hiding
- What’s the difference between
display: none,visibility: hidden, andaria-hidden="true"? - Which combinations make sense? Which are contradictory?
- Book Reference: “Inclusive Design Patterns” Ch. 2
- What’s the difference between
Questions to Guide Your Design (Project 2)
Before implementing, think through these:
- Priority Logic
- When both
roleattribute and implicit role exist, which wins? - If
aria-labelledbyandaria-labelboth exist, which is used? - Create a precedence table before coding
- When both
- State Extraction
- Will you store states as booleans, strings, or an enum?
- How will you handle invalid ARIA values (like
aria-expanded="yes"instead of"true")? - Should you validate against the ARIA spec or accept any value?
- Hidden Element Handling
- When you encounter
aria-hidden="true", do you stop processing that subtree? - What if an element is both
aria-hidden="true"AND focusable? (This is a bug—how will you report it?)
- When you encounter
Thinking Exercise (Project 2)
The ARIA Override Ladder
Study this progression:
<!-- Level 1: Native semantics -->
<button>Submit</button>
<!-- Screen reader: "Submit, button" -->
<!-- Level 2: ARIA override (valid) -->
<div role="button" tabindex="0">Submit</div>
<!-- Screen reader: "Submit, button" (but missing keyboard behavior!) -->
<!-- Level 3: ARIA override (contradictory) -->
<button role="link">Submit</button>
<!-- Screen reader: "Submit, link" (but acts like a button!) -->
<!-- Level 4: ARIA hidden (destructive) -->
<button aria-hidden="true">Submit</button>
<!-- Screen reader: (silence) but still focusable = keyboard trap! -->
Questions while analyzing:
- In Level 2, what’s missing beyond just the role?
- In Level 3, which is “right”—the native tag or the ARIA override?
- In Level 4, why is this almost always a mistake?
- How would your tool detect each of these problems?
The Interview Questions They’ll Ask (Project 2)
Prepare to answer these:
- “What is the difference between an element’s ‘role’ and its ‘state’?”
- “Can you override the role of a
<button>element? Should you?” - “When should you use
aria-hidden='true'vsdisplay: none?” - “What happens when you put
aria-expanded='false'on a<div>?” (Hint: nothing, unless you also give it a role!) - “Name three common ARIA mistakes that break accessibility.”
- “How do browsers decide which ARIA attributes to honor and which to ignore?”
Hints in Layers (Project 2)
Hint 1: Build on Project 1
Start with your semantic mapper from Project 1. Now add a step where you check for role attribute before using the implicit role.
Hint 2: The Role Precedence
IF element has role attribute:
Use explicit role (but validate it's a valid ARIA role)
ELSE:
Use implicit role from tag mapping
Hint 3: State Extraction Create a list of all valid ARIA state/property attributes:
const ariaStates = ['aria-expanded', 'aria-checked', 'aria-selected', 'aria-pressed'];
const ariaProps = ['aria-label', 'aria-labelledby', 'aria-describedby', 'aria-hidden'];
Loop through each, check if present, add to results.
Hint 4: Validation Compare your results to Chrome/Firefox DevTools Accessibility pane. Your tool should match exactly for:
- Role calculation
- State extraction
- Hidden element detection
Books That Will Help (Project 2)
| Topic | Book | Chapter |
|---|---|---|
| ARIA Fundamentals | “Inclusive Design Patterns” by Heydon Pickering | Ch. 1-2: “Principles and ARIA” |
| Role Override Rules | W3C ARIA Specification (online) | Section 3.2: “Implicit vs Explicit” |
| Common ARIA Errors | Common ARIA Mistakes | Full article |
| ARIA Patterns | WAI-ARIA Authoring Practices | “Design Patterns” section |
Common Pitfalls & Debugging (Project 2)
Problem 1: “My tool accepts role='superhero' as valid”
- Why: You’re not validating against the official ARIA role list
- Fix: Create an allowlist of valid roles from the ARIA spec (button, link, navigation, main, etc.)
- Quick test: Pass
<div role="notarole">— should return warning or fall back to no role
Problem 2: “aria-expanded shows up even on elements without a role”
- Why: ARIA states/properties only have meaning on elements with appropriate roles
- Fix: Check if the element’s role supports this attribute (e.g.,
aria-expandedneedsbutton,menu, etc.) - Quick test:
<div aria-expanded="true">should ignore the state (div has no role)
Problem 3: “Hidden elements still appear in my output”
- Why: You’re checking
aria-hiddenbut not CSSdisplay:noneorvisibility:hidden - Fix: Check computed styles (harder) or just handle
aria-hiddenfor now and document the limitation - Quick test: Parse
<div aria-hidden="true"><button>X</button></div>— button should NOT appear
Problem 4: “Role override on wrong element isn’t flagged”
- Why: You’re allowing any role on any element
- Fix: Check ARIA spec for forbidden roles. Example:
<input>cannot haverole="button" - Quick test:
<input role="button">should return warning
Learning Milestones (Project 2)
-
Milestone 1: ARIA Click → You understand that ARIA doesn’t add behavior, only semantics. A
<div role="button">is NOT keyboard-accessible without extra work. -
Milestone 2: Override Awareness → You can spot accessibility anti-patterns in real code (like
<button role="link">) and explain why they’re problematic. -
Milestone 3: The Hidden Trap → You understand the three types of hiding and when each is appropriate. You’ve learned
aria-hidden="true"is dangerous.
Project 3: The “AccName” Recursive Engine (The label calculator)
- File: ACCESSIBILITY_ENGINEERING_MASTERY.md
- Main Programming Language: TypeScript
- Alternative Programming Language: Rust, C++
- Coolness Level: Level 4: Hardcore Tech Flex
- Business Potential: 3. The “Service & Support” Model
- Difficulty: Level 4: Expert
- Knowledge Area: Specification Implementation / Algorithms
- Software or Tool: W3C AccName Spec
- Main Book: W3C AccName Specification (Online)
What you’ll build: A standalone implementation of the W3C “Accessible Name and Description Computation” algorithm. It takes a DOM node and returns the exact string a screen reader would announce.
Why it teaches a11y: This is the “boss fight” of accessibility engineering. You’ll learn the complex precedence rules: aria-labelledby > aria-label > alt > title > text content.
Core challenges you’ll face:
- Recursive References → maps to handling elements that point to other elements for their names
- Pseudo-element support → maps to accounting for ::before and ::after content
- CSS Hidden Check → maps to realizing display:none elements usually don’t contribute to names
Key Concepts:
- AccName Spec Steps: W3C AccName Computation 1.2 - All 14 steps
- Recursion for labelledby: Handling circular references
- Text Alternative Hierarchy: aria-labelledby > aria-label > alt > title > text content
Difficulty: Expert Time estimate: 2 weeks Prerequisites: Projects 1 & 2 completed, strong recursion skills, patience for specification reading
Real World Outcome (Project 3)
You’ll create a tool that can reliably predict what VoiceOver or NVDA will say for any element. This is the foundation of automated accessibility testing.
Example Output:
$ node accname.js "<button aria-label='Close Dialog'>X</button>"
Calculated Name: "Close Dialog"
Calculation Path: aria-label attribute
$ node accname.js "<img src='x.png' alt='Profile Picture'>"
Calculated Name: "Profile Picture"
Calculation Path: alt attribute (native semantics)
$ node accname.js "<button id='b1' aria-labelledby='label1 label2'>
<span id='label1'>Delete</span>
<span id='label2' aria-label='Your Account'></span>
</button>"
Calculated Name: "Delete Your Account"
Calculation Path: aria-labelledby referencing label1 + label2
Step 1: Found aria-labelledby='label1 label2'
Step 2: Resolved label1 text content = 'Delete'
Step 3: Resolved label2 aria-label = 'Your Account'
Step 4: Concatenated with space = 'Delete Your Account'
$ node accname.js "<a href='/home'>
<img src='icon.png' alt=''>
Home
</a>"
Calculated Name: "Home"
Calculation Path: text content (img has empty alt, excluded)
Note: Empty alt on decorative image is correct!
This is the most important project in the entire curriculum. Master this, and you understand how assistive technology interprets the web.
The Core Question You’re Answering (Project 3)
“When an element has five different possible labels, how does the computer pick just one?”
The AccName spec is the “Source of Truth” for the entire internet’s auditory experience. Implementing it means you understand the priority of information and why aria-labelledby always wins over aria-label, which always wins over alt, and so on.
Before starting, ask yourself: “If I were blind and using a screen reader, which label would I want to hear first?”
Concepts You Must Understand First (Project 3)
Stop and research these before coding:
- The 14-Step AccName Algorithm
- What is step 2A vs 2B of the spec?
- Why does
aria-labelledbycome beforearia-label? - When does the algorithm recurse into children for their text?
- Resource: W3C AccName Computation 1.2 Spec (read steps 2A-2I carefully)
- ID Reference Resolution
- How do you find an element by ID in your DOM parser?
- What happens when
aria-labelledby="id1 id2 id3"(multiple IDs)? - What if an ID doesn’t exist? (Return empty string, don’t crash)
- Book Reference: “Eloquent JavaScript” Ch. 13 (getElementById)
- Text Content Traversal
- How do you get all text from an element, including nested children?
- Should
<style>and<script>tags contribute text? (No!) - What about
::beforeand::afterpseudo-elements? (Yes, if visible!) - Resource: MDN “textContent vs innerText vs innerHTML”
- Hidden Element Filtering
- Elements with
aria-hidden="true"don’t contribute to names (usually) - Elements with
display: noneorvisibility: hiddenalso don’t contribute - Exception:
aria-labelledbycan reference hidden elements! - Resource: AccName Spec Section 4 “Computation Steps”
- Elements with
Questions to Guide Your Design (Project 3)
Before implementing, think through these:
- Algorithm Implementation
- Will you implement all 14 steps of the spec, or start with the most common (2A-2F)?
- How will you structure your code to match the spec’s step numbering? (Makes debugging easier)
- Should you return just the final name, or also the “calculation path” for debugging?
- Recursion Handling
- The algorithm calls itself when resolving
aria-labelledbyreferences - How will you prevent infinite loops? (Track visited elements)
- What’s your base case? (Leaf text nodes)
- The algorithm calls itself when resolving
- Edge Cases
- What if
aria-labelledbyreferences the element itself? (Circular reference—skip it) - What if an
<img>has bothalt=""(empty) and atitleattribute? - How do you handle concatenation when joining multiple label sources?
- What if
Thinking Exercise (Project 3)
Trace the AccName Calculation
Manually calculate the accessible name for this complex example:
<button id="btn" aria-labelledby="l1 btn l2">
Default Text
</button>
<span id="l1">Save</span>
<span id="l2" aria-label="the document"></span>
Steps to trace:
- Check step 2A: Is
aria-labelledbypresent? YES →"l1 btn l2" - Resolve
l1: Get text content of span#l1 ="Save" - Resolve
btn: Get text content of button#btn ="Default Text" - Resolve
l2: Check aria-label on span#l2 ="the document" - Concatenate with spaces:
"Save Default Text the document"
Final AccName: "Save Default Text the document"
Did you get it right? This is exactly how the algorithm works. Now implement it.
The Interview Questions They’ll Ask (Project 3)
Prepare to answer these:
- “What is the accessible name calculation algorithm?”
- “Which has higher priority:
aria-labeloraria-labelledby?” - “Can
aria-labelledbyreference a hidden element?” (Yes!) - “What happens if an
<img>hasalt=''(empty string)?” (It’s decorative, no name) - “How do you prevent infinite loops when aria-labelledby references create cycles?”
- “Why does the AccName algorithm have 14 steps instead of just using the first label found?”
- “What’s the difference between
textContentandinnerTextfor AccName purposes?”
Hints in Layers (Project 3)
Hint 1: Start Simple Implement just steps 2A, 2B, and 2F first:
- 2A:
aria-labelledby(ID reference) - 2B:
aria-label(direct string) - 2F:
textContent(leaf text)
This handles 80% of real-world cases.
Hint 2: The ID Resolver
For aria-labelledby="id1 id2":
const ids = element.getAttribute('aria-labelledby').split(' ');
const parts = ids.map(id => {
const refElement = document.getElementById(id);
return refElement ? calculateAccName(refElement) : ''; // RECURSION
});
return parts.join(' ');
Hint 3: Visited Set for Cycles Track which elements you’ve already processed:
function calculateAccName(element, visited = new Set()) {
if (visited.has(element)) return ''; // Prevent infinite loop
visited.add(element);
// ... rest of algorithm
}
Hint 4: Testing Against the Spec Create test HTML files with known AccNames (check in browser DevTools):
- Test
aria-labelledbywith multiple IDs - Test
alton images - Test nested text content
- Test hidden element references
Your tool should match browser calculation exactly.
Books That Will Help (Project 3)
| Topic | Book | Chapter |
|---|---|---|
| AccName Specification | W3C AccName Computation 1.2 (online) | Full spec (focus on Section 4) |
| Recursion Patterns | “Grokking Algorithms” by Aditya Bhargava | Ch. 3: “Recursion” |
| DOM Traversal | “Eloquent JavaScript” by Marijn Haverbeke | Ch. 13: “DOM” |
| Algorithmic Thinking | “Algorithmic Thinking” by Daniel Zingaro | Ch. 1: “Recursion and Memoization” |
Common Pitfalls & Debugging (Project 3)
Problem 1: “My tool returns different names than the browser”
- Why: You’re not following the exact spec step order, or missing edge cases
- Fix: Print debug output showing which step was used (2A? 2B? 2F?)
- Quick test: Create a page with both
aria-labelandaria-labelledby—labelledby should win
Problem 2: “Stack overflow when aria-labelledby creates a cycle”
- Why: Element A references B, B references A → infinite recursion
- Fix: Pass a
Setof visited elements, skip if already seen - Quick test:
<div id="a" aria-labelledby="b"></div><div id="b" aria-labelledby="a"></div>
Problem 3: “Empty string returned for buttons with text content”
- Why: You’re returning early before reaching step 2F (text content)
- Fix: Make sure to fall through all steps until you find a name
- Quick test:
<button>Click Me</button>should return “Click Me”
Problem 4: “Hidden elements contribute to names when they shouldn’t”
- Why: You’re not checking
aria-hiddenor CSSdisplay: nonebefore traversing children - Fix: Filter out hidden elements unless they’re referenced by
aria-labelledby(exception!) - Quick test:
<button><span aria-hidden="true">X</span>Close</button>should return “Close” only
Problem 5: “Pseudo-element content (::before/::after) is missing”
- Why:
textContentdoesn’t include generated content—this requires CSS OM access - Fix: Document this as a known limitation for now (very advanced) or use
getComputedStyle - Quick test: If button has
::before {content: 'X'}, full browsers include it—your tool might not (acceptable)
Learning Milestones (Project 3)
-
Milestone 1: The Spec Makes Sense → You’ve read the AccName specification and understand why each step exists. The 14 steps aren’t arbitrary—they reflect priority of authorial intent.
-
Milestone 2: Recursion Mastery → You’ve implemented
aria-labelledbyresolution with proper cycle detection. You can explain how the algorithm calls itself. -
Milestone 3: Browser-Level Accuracy → Your tool matches Chrome/Firefox DevTools Accessibility pane for 95%+ of elements. You’ve internalized the most complex accessibility algorithm on the web.
Real World Outcome (Project 2)
You’ll be able to feed your tool a complex React component and see exactly how the role is being “forced” by the developer.
Example Output:
$ node resolve_aria.js component.html
Input: <li role="menuitem" aria-haspopup="true">Settings</li>
Output Role: menuitem
Output State: haspopup=true
The Core Question You’re Answering (Project 2)
“How do I make a generic <div> act like a complex widget without writing a whole browser engine?”
ARIA is a “promise” you make to the browser. This project teaches you exactly which promises the A-Tree trusts and which ones it ignores.
Real World Outcome (Project 3)
You’ll create a tool that can reliably predict what VoiceOver or NVDA will say for any element. This is the foundation of automated accessibility testing.
Example Output:
$ node accname.js "<button aria-label='Close Dialog'>X</button>"
Calculated Name: "Close Dialog"
$ node accname.js "<img src='x.png' alt='Profile Picture'>"
Calculated Name: "Profile Picture"
The Core Question You’re Answering (Project 3)
“When an element has five different possible labels, how does the computer pick just one?”
The AccName spec is the “Source of Truth” for the entire internet’s auditory experience. Implementing it means you understand the priority of information.
Project 4: Keyboard Trap Detector (Focus Management)
- File: ACCESSIBILITY_ENGINEERING_MASTERY.md
- Main Programming Language: TypeScript/Playwright
- Alternative Programming Languages: Python/Selenium
- Coolness Level: Level 3: Genuinely Clever
- Business Potential: 3. The “Service & Support” Model
- Difficulty: Level 3: Advanced
- Knowledge Area: Focus Management / Browser Automation
- Software or Tool: Playwright or Puppeteer
- Main Book: “Inclusive Design Patterns” by Heydon Pickering
What you’ll build: A tool that automatically navigates through a page using only Tab keys and detects “Keyboard Traps”—areas where the focus gets stuck and cannot exit.
Why it teaches a11y: Keyboard accessibility is the #1 failure in modern web apps. This project teaches you about tabindex, focusable elements, and the lifecycle of the document.activeElement.
Core challenges you’ll face:
- Simulating Sequential Navigation → maps to understanding the DOM’s focus order
- Detecting Focus Loops → maps to identifying modals that don’t trap focus correctly
- Handling Asynchronous UI → maps to waiting for menus to open before checking focus
Key Concepts:
- Focus Order: WCAG Success Criterion 2.4.3
- Focusable Elements: MDN “Focusable elements” list
Difficulty: Advanced Time estimate: 1 week
Project 5: Contrast Ratio Engine (Luminance Math)
- File: ACCESSIBILITY_ENGINEERING_MASTERY.md
- Main Programming Language: JavaScript
- Alternative Programming Languages: Python, C
- Coolness Level: Level 2: Practical but Forgettable
- Business Potential: 2. The “Micro-SaaS / Pro Tool”
- Difficulty: Level 2: Intermediate
- Knowledge Area: Color Theory / Mathematics
- Software or Tool: WCAG 2.1 Contrast Formula
- Main Book: “Accessibility for Everyone” by Laura Kalbag
What you’ll build: A library that calculates the contrast ratio between two colors using the Relative Luminance formula defined in WCAG.
Why it teaches a11y: It moves “color contrast” from a subjective opinion to a mathematical certainty. You’ll learn about sRGB gamma correction and the logarithmic nature of human sight.
Core challenges you’ll face:
- sRGB to Linear RGB → maps to understanding how screens display light
- The Luminance Formula → maps to implementing (0.2126R + 0.7152G + 0.0722B)*
- Opacity Blending → maps to calculating contrast when one color is semi-transparent
Key Concepts:
- Relative Luminance: WCAG 2.1 Glossary
- Contrast Ratio (Minimum): WCAG Success Criterion 1.4.3
Difficulty: Intermediate Time estimate: Weekend
Project 6: The CLI Screen Reader (TTS Output)
- File: ACCESSIBILITY_ENGINEERING_MASTERY.md
- Main Programming Language: Node.js
- Alternative Programming Languages: Python
- Coolness Level: Level 4: Hardcore Tech Flex
- Business Potential: 1. The “Resume Gold”
- Difficulty: Level 3: Advanced
- Knowledge Area: OS Integration / Text-to-Speech
- Software or Tool:
saycommand (macOS) orespeak(Linux) - Main Book: “A Web for Everyone” by Sarah Horton
What you’ll build: A tool that combines your A-Tree parser (Project 1) and your AccName engine (Project 3). It “reads” the page aloud to you via your computer’s speakers as you navigate with your keyboard.
Why it teaches a11y: This is the culmination of the “Semantic Bridge.” You finally experience the web as a purely auditory interface. You’ll realize how annoying “redundant alt text” or “unlabeled buttons” truly are.
Core challenges you’ll face:
- Buffer Management → maps to stopping the voice when a new key is pressed
- Verbosity Control → maps to deciding when to say “Button” vs just the name
- Navigation State → maps to tracking where the “virtual cursor” is
Project 7: The Mutation Tracker (Watching the A-Tree change)
- File: ACCESSIBILITY_ENGINEERING_MASTERY.md
- Main Programming Language: JavaScript/Browser Extension
- Alternative Programming Languages: N/A
- Coolness Level: Level 3: Genuinely Clever
- Business Potential: 3. The “Service & Support” Model
- Difficulty: Level 3: Advanced
- Knowledge Area: Browser Internals / MutationObservers
- Software or Tool: MutationObserver API
- Main Book: “Eloquent JavaScript” by Marijn Haverbeke
What you’ll build: A browser extension that watches the DOM for changes (adding/removing nodes) and prints a log of how those changes affect the Accessibility Tree.
Why it teaches a11y: Modern Single Page Apps (SPAs) are dynamic. This project teaches you about “Live Regions” (aria-live) and how the A-Tree is updated incrementally without a page reload.
Core challenges you’ll face:
- Batching Mutations → maps to handling 100 DOM changes in a single tick
- A-Tree Diffing → maps to calculating only the semantic change, ignoring visual-only changes
- Performance → maps to ensuring the observer doesn’t crash the browser
Key Concepts:
- ARIA Live Regions:
politevsassertiveupdates. - Incremental Updates: How AT is notified of DOM changes.
Project 8: Complex Table Parser (Navigating 2D Grids)
- File: ACCESSIBILITY_ENGINEERING_MASTERY.md
- Main Programming Language: TypeScript
- Alternative Programming Languages: Python
- Coolness Level: Level 3: Genuinely Clever
- Business Potential: 1. The “Resume Gold”
- Difficulty: Level 3: Advanced
- Knowledge Area: Data Structures / Grids
- Software or Tool: HTML Table Specification
- Main Book: “Accessibility for Everyone” by Laura Kalbag
What you’ll build: A tool that parses an HTML table, including colspan, rowspan, and scope attributes, and maps every data cell to its corresponding headers.
Why it teaches a11y: Tables are the most complex semantic structures. This project forces you to understand how th and td relationships are serialized for screen readers so a user can ask “What is the header for this cell?”.
Core challenges you’ll face:
- Grid Mapping → maps to representing a 2D array from 1D HTML tags
- Header Association → maps to implementing the algorithm for finding headers in complex tables
- Scope Resolution → maps to understanding how ‘col’ and ‘row’ scopes change cell meaning
Key Concepts:
- Table Semantics: W3C Table Accessibility Tutorials.
- AccName for Cells: How cell contents are calculated.
Project 9: Focus Order Visualizer (SVG Mapping)
- File: ACCESSIBILITY_ENGINEERING_MASTERY.md
- Main Programming Language: JavaScript/Canvas
- Alternative Programming Languages: N/A
- Coolness Level: Level 5: Pure Magic (Super Cool)
- Business Potential: 5. The “Industry Disruptor”
- Difficulty: Level 4: Expert
- Knowledge Area: Computational Geometry / Visualization
- Software or Tool: Playwright + HTML Canvas
- Main Book: “Inclusive Design Patterns” by Heydon Pickering
What you’ll build: A tool that takes a screenshot of a website and draws a “connecting line” (SVG path) between every focusable element in the order they appear to a keyboard user.
Why it teaches a11y: It makes the “invisible” focus order visible. You’ll immediately see if the “Contact” button comes before the “Search” bar unexpectedly. It teaches the impact of tabindex and z-index.
Core challenges you’ll face:
- Coordinate Extraction → maps to getting the exact (x,y) of a focusable element
- Ordering Algorithm → maps to mimicking the browser’s “Source Order” logic
- Visual Clutter Management → maps to drawing paths that don’t overlap too much
Project 10: The “Alt Text” Context Engine (LLM-Aided)
- File: ACCESSIBILITY_ENGINEERING_MASTERY.md
- Main Programming Language: Python/TypeScript
- Alternative Programming Languages: N/A
- Coolness Level: Level 4: Hardcore Tech Flex
- Business Potential: 2. The “Micro-SaaS / Pro Tool”
- Difficulty: Level 3: Advanced
- Knowledge Area: AI / Natural Language Processing
- Software or Tool: OpenAI API or local Llama model
- Main Book: “A Web for Everyone” by Sarah Horton
What you’ll build: A tool that crawls a page, finds images with missing or bad alt text (like “image1.jpg”), and uses an LLM to generate descriptive alt text based on the surrounding text context and the image itself.
Why it teaches a11y: It teaches you the difference between “Description” and “Context.” Alt text shouldn’t just describe the image; it should explain why the image is there.
Project Comparison Table
| Project | Difficulty | Time | Depth of Understanding | Fun Factor |
|---|---|---|---|---|
| 1. Semantic Tag Mapper | Level 1 | Weekend | High (Foundation) | ⭐⭐⭐ |
| 2. ARIA Resolver | Level 2 | 1 week | High (Overrides) | ⭐⭐⭐ |
| 3. AccName Engine | Level 4 | 2 weeks | Elite (Logic) | ⭐⭐⭐⭐ |
| 4. Keyboard Trap Detector | Level 3 | 1 week | High (Focus) | ⭐⭐⭐ |
| 5. Contrast Ratio Engine | Level 2 | Weekend | Medium (Visuals) | ⭐⭐ |
| 6. CLI Screen Reader | Level 3 | 2 weeks | Extreme (Experience) | ⭐⭐⭐⭐⭐ |
| 7. Mutation Tracker | Level 3 | 1 week | High (Dynamic) | ⭐⭐⭐ |
| 8. Complex Table Parser | Level 3 | 1 week | High (Grid) | ⭐⭐ |
| 9. Focus Visualizer | Level 4 | 1 week | Extreme (Spatial) | ⭐⭐⭐⭐⭐ |
| 10. Alt Text AI Engine | Level 3 | 1 week | High (Context) | ⭐⭐⭐⭐ |
Recommendation
If you are a total beginner: Start with Project 1 (Semantic Tag Mapper). It is the quickest way to see the “invisible tree” that powers accessibility.
If you want to be a professional a11y auditor: Master Project 3 (AccName Engine) and Project 4 (Keyboard Trap Detector). These two cover 80% of real-world accessibility issues.
If you want to build something “wow” for a portfolio: Build Project 9 (Focus Order Visualizer). It turns an abstract engineering concept into a beautiful, visual story.
Final Overall Project: The “Open AOM” Auditor
What you’ll build: A comprehensive, open-source accessibility auditing engine that combines all previous projects into a single dashboard.
- It parses the page into an AOM (Projects 1, 2, 7).
- It calculates every name via AccName (Project 3).
- It verifies color contrast and keyboard focus (Projects 4, 5).
- It generates a visual “Focus Map” (Project 9).
- It provides a “Listen Mode” to preview the page (Project 6).
Why this is the final boss: You aren’t just using an existing library like axe-core; you’ve built the engine from the ground up. You understand exactly why an error is thrown because you wrote the logic that calculates the name and role of every element.
Summary
This learning path covers Accessibility Engineering through 10 hands-on projects. Here’s the complete list:
| # | Project Name | Main Language | Difficulty | Time Estimate |
|---|---|---|---|---|
| 1 | Semantic Tag Mapper | TypeScript | Level 1 | Weekend |
| 2 | ARIA Resolver | TypeScript | Level 2 | 1 week |
| 3 | AccName Engine | TypeScript | Level 4 | 2 weeks |
| 4 | Keyboard Trap Detector | Playwright | Level 3 | 1 week |
| 5 | Contrast Ratio Engine | JavaScript | Level 2 | Weekend |
| 6 | CLI Screen Reader | Node.js | Level 3 | 2 weeks |
| 7 | Mutation Tracker | JavaScript | Level 3 | 1 week |
| 8 | Complex Table Parser | TypeScript | Level 3 | 1 week |
| 9 | Focus Visualizer | JavaScript | Level 4 | 1 week |
| 10 | Alt Text AI Engine | Python/TS | Level 3 | 1 week |
Recommended Learning Path
For beginners: Start with projects #1, #2, #5 For intermediate: Jump to projects #4, #7, #8 For advanced: Focus on projects #3, #6, #9, #10
Expected Outcomes
After completing these projects, you will:
- Understand the 14-step AccName calculation algorithm better than most senior developers.
- Be able to implement custom ARIA widgets (tabs, comboboxes) that are fully functional.
- Know how to bridge the gap between DOM mutations and Accessibility Tree updates.
- Understand the physics and mathematics of color contrast and light.
- Have built a portfolio of tools that demonstrate “hardcore” accessibility engineering skills.