{"id":"l-a11y-5-3","courseId":"web-accessibility","lang":"en","kind":"lesson","summary":"Run a structured WCAG 2.2 AA audit of a whole page or flow, prioritise what you find, and build accessibility into design, development and QA so it stays fixed.","html":"<p>Over seventeen lessons you have repaired Ticketly one slice at a time. An audit is how you prove the whole thing works, and how you find what slipped between the slices. Then comes the harder problem: keeping it that way when five developers, two designers and a marketing team change it every week.</p>\n<h2 id=\"sec-1\" tabindex=\"-1\">A structured audit</h2>\n<p>W3C’s evaluation methodology, <strong>WCAG-EM</strong>, gives the shape. Here it is applied to Ticketly:</p>\n<ol>\n<li><strong>Scope and target.</strong> “Ticketly web app, WCAG 2.2 Level AA, latest Chrome, Firefox and Safari, NVDA and VoiceOver.” Writing it down stops the audit from sprawling, or from quietly skipping the hard parts.</li>\n<li><strong>Explore and sample.</strong> List the key flows: find an event, book tickets, pay, manage a booking. Choose representative pages, and include each <strong>complete process</strong> end to end. WCAG conformance covers whole processes, and many failures, like lost focus after a step or re-asking for the email address, only show up between pages.</li>\n<li><strong>Automated scan.</strong> Run axe on every sampled page <strong>and state</strong>: dialogs open, menus expanded, form errors showing, dark theme on. Fix or log the results; they are the cheap ones.</li>\n<li><strong>Keyboard pass.</strong> Every flow, without a mouse, using the checklist from <a href=\"/lesson/web-accessibility/l-a11y-5-2\">Testing with a Keyboard and Screen Readers</a>.</li>\n<li><strong>Screen reader pass.</strong> The same flows with NVDA and Chrome, VoiceOver and Safari, and VoiceOver on iOS for the mobile layout.</li>\n<li><strong>Visual and content checks.</strong> 400% zoom and 320px reflow, text spacing, non-text contrast, reduced motion, alt text quality, headings, link text, language of parts.</li>\n<li><strong>Report and prioritise.</strong> Each finding with its location, steps, WCAG criterion, severity and a suggested fix.</li>\n<li><strong>Fix and retest</strong> the same flows, then update the accessibility statement.</li>\n</ol>\n<figure class=\"diagram\"><svg class=\"diagram-svg\" focusable=\"false\" viewBox=\"0 0 700 170\" role=\"img\" aria-labelledby=\"l-a11y-5-3-t1\"><defs><marker id=\"arrow-l-a11y-5-3-1\" viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\" markerWidth=\"7\" markerHeight=\"7\" orient=\"auto-start-reverse\"><path d=\"M0 0 L10 5 L0 10 z\" class=\"d-arrowhead\"/></marker></defs>\n  <title id=\"l-a11y-5-3-t1\">Four stages in a row: Scope and sample, then Automated scan of pages and states, then Manual passes with keyboard, screen readers, zoom and content, then Report, fix and retest, with an arrow looping back from retest to the manual passes.</title>\n  <rect class=\"d-box\" x=\"10\" y=\"45\" width=\"150\" height=\"70\" rx=\"10\"/>\n  <text class=\"d-label\" x=\"85\" y=\"75\" text-anchor=\"middle\">Scope +</text>\n  <text class=\"d-label\" x=\"85\" y=\"97\" text-anchor=\"middle\">sample</text>\n  <path class=\"d-arrow\" d=\"M160 80 L185 80\" marker-end=\"url(#arrow-l-a11y-5-3-1)\"/>\n  <rect class=\"d-box-accent\" x=\"190\" y=\"45\" width=\"150\" height=\"70\" rx=\"10\"/>\n  <text class=\"d-label\" x=\"265\" y=\"75\" text-anchor=\"middle\">Automated</text>\n  <text class=\"d-label\" x=\"265\" y=\"97\" text-anchor=\"middle\">pages + states</text>\n  <path class=\"d-arrow\" d=\"M340 80 L365 80\" marker-end=\"url(#arrow-l-a11y-5-3-1)\"/>\n  <rect class=\"d-box-primary\" x=\"370\" y=\"45\" width=\"150\" height=\"70\" rx=\"10\"/>\n  <text class=\"d-label\" x=\"445\" y=\"75\" text-anchor=\"middle\">Manual: keys,</text>\n  <text class=\"d-label\" x=\"445\" y=\"97\" text-anchor=\"middle\">SR, zoom, text</text>\n  <path class=\"d-arrow\" d=\"M520 80 L545 80\" marker-end=\"url(#arrow-l-a11y-5-3-1)\"/>\n  <rect class=\"d-box-success\" x=\"550\" y=\"45\" width=\"140\" height=\"70\" rx=\"10\"/>\n  <text class=\"d-label\" x=\"620\" y=\"75\" text-anchor=\"middle\">Report, fix,</text>\n  <text class=\"d-label\" x=\"620\" y=\"97\" text-anchor=\"middle\">retest</text>\n  <path class=\"d-arrow d-dashed\" d=\"M620 115 C620 160 445 160 445 120\" marker-end=\"url(#arrow-l-a11y-5-3-1)\"/>\n  <text class=\"d-label-muted\" x=\"530\" y=\"160\" text-anchor=\"middle\">retest the same flows</text>\n</svg><figcaption>Ticketly’s audit, from scope to retest</figcaption></figure>\n<h2 id=\"sec-2\" tabindex=\"-1\">Prioritising what you find</h2>\n<p>A first audit of a real product often lists dozens or hundreds of issues. Rank them by what they do to people:</p>\n<ul>\n<li><strong>Critical:</strong> blocks a key task for some users. An unlabelled card number field, a keyboard trap in the payment dialog, a CAPTCHA with no alternative.</li>\n<li><strong>Serious:</strong> the task is possible but very hard. Missing headings on a long page, errors that aren’t announced.</li>\n<li><strong>Moderate:</strong> friction and confusion. Vague link text, low contrast on secondary text.</li>\n<li><strong>Minor:</strong> polish. A decorative icon announced as “graphic”.</li>\n</ul>\n<p>Then weight by traffic and flow: a serious issue in checkout outranks a moderate one on the careers page. Fixing ten critical issues in the booking flow does more for disabled customers than fixing a hundred minor ones elsewhere.</p>\n<aside class=\"callout callout-mistake\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\"/><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/></svg><span><span class=\"callout-kind\">Common mistake</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>Fixing the instance instead of the component</span></p>\n<p>The audit says “Book now button on the Friday card has no unique name”. Someone fixes that one button. There are 240 event cards, all rendered by the same component. Always ask where an issue comes from, and fix it in the shared component, token or template, so the fix reaches every page at once.</p>\n</aside>\n<h2 id=\"sec-3\" tabindex=\"-1\">Building it into the team</h2>\n<p>Audits find problems after they are built. Lasting accessibility comes from catching them at every stage, at the point where they are cheapest to fix.</p>\n<p><strong>Design.</strong> Annotate designs with the information developers can’t see in a picture: the heading structure, landmarks, focus order, accessible names for icon buttons, error messages, what moves and its reduced-motion alternative. Verify colour tokens against contrast ratios once, so every screen inherits them. Design focus and error states, not just default and hover.</p>\n<p><strong>Components.</strong> A shared component library is the biggest lever you have. If the <code dir=\"ltr\">Dialog</code>, <code dir=\"ltr\">Tabs</code>, <code dir=\"ltr\">Button</code> and <code dir=\"ltr\">TextField</code> components are accessible, every feature built from them starts accessible, and a fix in one place fixes everything.</p>\n<p><strong>Development.</strong> Lint with <code dir=\"ltr\">eslint-plugin-jsx-a11y</code>, run axe in component and end-to-end tests, and make a two-minute keyboard check part of every pull request. Locating elements by role and name in tests, as Playwright and Testing Library encourage, keeps names honest.</p>\n<p><strong>QA and definition of done.</strong> A story isn’t done until it works with a keyboard and has been checked with one screen reader. Accessibility bugs go in the normal backlog with normal severities; a separate list tends to become the list nobody schedules.</p>\n<p><strong>Content and procurement.</strong> Editors write alt text and plain-language copy; train them, and give the CMS a required alt field. When you buy third-party widgets such as a payment form or a chat tool, ask for an Accessibility Conformance Report and test it yourself, because their barriers become yours.</p>\n<aside class=\"callout callout-why\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><circle cx=\"12\" cy=\"12\" r=\"6\"/><circle cx=\"12\" cy=\"12\" r=\"2\"/></svg><span><span class=\"callout-kind\">Why this matters</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>Why this matters</span></p>\n<p>The European Accessibility Act and similar laws require you to describe how your service meets accessibility requirements, which in practice means publishing an accessibility statement. An honest statement listing known issues and a contact for help is far better than a claim of full compliance nobody has tested. Users with a way to report problems become your best testers.</p>\n</aside>\n<h2 id=\"sec-4\" tabindex=\"-1\">Where Ticketly ended up</h2>\n<p>Ticketly now has landmarks and a heading outline, real buttons and links, labelled forms with announced errors, considered alt text and a proper pricing table. It works from the keyboard with a skip link and visible focus, has a native booking dialog, ARIA tabs and live status messages, passes contrast, reflows at 400% zoom, respects reduced motion, names every control and pronounces its Arabic correctly. Most importantly, it has axe in CI and a team that checks with a keyboard before merging.</p>\n<p>Samir booked his tickets for Harbour Lights himself this year, in under two minutes, without phoning anyone. That is the whole point.</p>\n","toc":[{"id":"sec-1","text":"A structured audit","level":2},{"id":"sec-2","text":"Prioritising what you find","level":2},{"id":"sec-3","text":"Building it into the team","level":2},{"id":"sec-4","text":"Where Ticketly ended up","level":2}],"takeaways":["An audit has a defined scope and target, a representative sample including complete flows, automated plus manual testing, and a prioritised report.","Prioritise by impact on real tasks; a blocker in checkout outranks a dozen minor issues on the About page.","Accessibility lasts when it is part of every stage, from design annotations and accessible components to lint rules, CI scans and a definition of done.","Accessibility bugs are bugs; keep them in the normal backlog with normal severities, not in a separate list that never gets scheduled."],"further":[{"title":"W3C WAI: WCAG-EM Overview (Website Accessibility Conformance Evaluation Methodology)","url":"https://www.w3.org/WAI/test-evaluate/conformance/wcag-em/"},{"title":"W3C WAI: Planning and Managing Web Accessibility","url":"https://www.w3.org/WAI/planning-and-managing/"},{"title":"W3C WAI: Developing an Accessibility Statement","url":"https://www.w3.org/WAI/planning/statements/"}],"quiz":[{"q":"<p>Your audit of Ticketly found 60 issues and you have one sprint. Which should be fixed first?</p>","options":[{"text":"The 30 low-contrast footer links, because they are the most numerous","why":"Volume isn’t impact. Footer links are rarely the reason someone can’t buy a ticket."},{"text":"Whatever axe reported, because automated findings are the most objective","why":"Some of the most serious problems, like a focus trap in checkout, are never reported by axe. Prioritise by impact, not by source."},{"text":"Issues on the About page, because they are easiest and show quick progress","why":"Quick wins have a place, but leaving checkout broken means disabled customers still can’t complete a purchase."},{"text":"The unlabelled card number field and the keyboard trap in the payment dialog, because they block purchases","why":"Correct. Blockers in the most important flows come first; they stop people from completing the task at all."}],"answer":3},{"q":"<p>Why should an audit sample include complete processes, such as the whole booking flow, and not only individual pages?</p>","options":[{"text":"Because WCAG conformance requires every page in a process to conform, and failures often appear between steps","why":"Correct. WCAG’s conformance requirements cover complete processes, and focus handling, error recovery and redundant entry only show up when you move through them."},{"text":"Because automated tools can only scan multi-page flows","why":"Automated tools scan individual pages and states. Flows matter because of what a person experiences between steps."},{"text":"Because single pages are always accessible","why":"Single pages fail all the time. The point is that testing pages alone misses problems that only appear across a flow."}],"answer":0},{"q":"<p>Which practice does the most to keep Ticketly accessible as new features ship?</p>","options":[{"text":"A full external audit every two years","why":"Audits are valuable checkpoints, but two years of unchecked changes will reintroduce most of the problems."},{"text":"Accessibility in the definition of done, with accessible shared components, axe in CI and a keyboard check before merging","why":"Correct. When every feature passes through the same gates, accessibility is maintained continuously instead of repaired periodically."},{"text":"A separate “accessibility backlog” reviewed at the end of each quarter","why":"A separate backlog signals that these are optional extras and tends to be deprioritised. Accessibility bugs belong in the normal backlog."}],"answer":1}],"exercise":{"kind":"order","items":["scope","sample","automated","keyboard","screen-reader","visual-content","report","retest"],"title":"Plan Ticketly's audit","prompt":"<p>You have been asked to audit Ticketly against WCAG 2.2 AA before the festival’s ticket launch. Put the audit steps in the order you would carry them out.</p>\n","hints":["You can’t choose pages until you know what you are auditing against and which flows matter.","Do the cheap, fast automated checks before the slower manual passes, so the manual testers aren’t distracted by missing labels.","Testing ends with a sweep of the visual and content checks the tool and the two passes don’t cover. The report comes after all testing, and the work isn’t finished until fixes are retested."],"explanation":"<p>An audit starts by fixing its <strong>scope and target</strong>, so everyone agrees what “done” means. The <strong>sample</strong> then picks representative pages and complete flows. <strong>Automated scans</strong> come first among the tests because they are fast and clear away the obvious problems. The <strong>keyboard pass</strong> precedes the <strong>screen reader pass</strong> because keyboard failures (unreachable controls, traps) block screen reader testing too. <strong>Visual and content checks</strong> cover what neither tool reveals. The <strong>report</strong> prioritises by impact, and the cycle closes with fixes, a <strong>retest</strong> of the same flows and an updated accessibility statement.</p>\n","checkLabels":{},"itemText":{"scope":"Agree the scope and target: WCAG 2.2 AA, the browsers and assistive technologies, and the key flows","sample":"Choose a sample: home, event page, checkout and account pages, plus the complete booking flow","automated":"Run axe on every sampled page and state, including open dialogs and form errors","keyboard":"Do a keyboard pass through every flow: reach, see, operate, escape","screen-reader":"Repeat the flows with NVDA and Chrome, VoiceOver and Safari, and VoiceOver on iOS","visual-content":"Check 400% zoom, text spacing, reduced motion, alt text quality, headings and language","report":"Write findings with location, WCAG criterion, severity and fix, and prioritise blockers in key flows","retest":"Fix the issues, retest the same flows and update the accessibility statement"}},"words":895,"readMinutes":4}