WCAG 2.2 AA is not a Lighthouse score you chase the week before launch. On Sitecore sites, most accessibility defects are authored: missing alt text, link text that says "click here," carousels without pause, focus rings removed in CSS, and tap targets that only work for mouse users. This field note starts with the principles, shows how Axe and Lighthouse fit a Sitecore delivery pipeline, then drills into component-level patterns that keep authors from breaking AA after go-live.
Executive Summary
Regulated brands (pharma HCP/DTC, financial, public sector) increasingly require WCAG 2.2 Level AA in contracts. Sitecore teams that treat accessibility as a front-end-only checklist miss the CMS half of the problem. Templates, validation, and rendering defaults decide whether authors can ship inaccessible content by accident.
- Standard: WCAG 2.2 AA is the practical bar for most US public and enterprise sites.
- Tools: Axe catches many automated issues; Lighthouse is a CI signal, not a certificate; manual keyboard and screen reader passes remain mandatory.
- Sitecore angle: Encode a11y into datasource fields, rendering parameters, and rich text rules so the CMS pushes authors toward compliant content.
- 2.2 additions: Pay attention to focus not obscured, dragging, target size (24×24 AA floor), and help patterns that 2.1 teams often skipped.
Basics: POUR and What AA Means
WCAG organizes requirements under four principles (POUR):
| Principle | Plain meaning | Sitecore examples |
|---|---|---|
| Perceivable | Users can sense the content | Alt text fields, captions, contrast tokens |
| Operable | Users can use the UI | Keyboard nav, pause on carousels, target size |
| Understandable | Users can understand content and UI | Clear labels, error text, consistent nav |
| Robust | Content works with assistive tech | Valid HTML, ARIA used correctly, name/role/value |
Level A is the floor. Level AA is what most RFPs mean by "accessible." Level AAA is rarely a full-site contractual bar. Official standard: WCAG 2.2.
What Changed in WCAG 2.2 (Practical for Component Teams)
| 2.2 focus area | Why Sitecore teams care | Component hint |
|---|---|---|
| Focus not obscured (2.4.11 AA) | Sticky headers and cookie banners cover focus | Reserve space; do not steal focus under chrome |
| Dragging movements (2.5.7 AA) | Drag-only carousels or sliders | Provide button alternatives |
| Target size (minimum) (2.5.8 AA) | Footer link farms, icon-only controls | 24×24 CSS px AA floor (or spacing exception); ship chrome/icon controls at 44×44 as the practical bar (AAA 2.5.5 / platform HIG) |
| Consistent help | Help links moving per template | Shared chrome for help/contact patterns |
| Accessible authentication | HCP gates, login walls | Avoid cognitive function tests as the only path |
Tooling: Axe, Lighthouse, and What They Do Not Catch
Axe (Deque)
Axe DevTools and @axe-core/cli / Playwright axe integrations flag many automated WCAG failures: missing names, color contrast on text nodes, ARIA misuse, duplicate IDs. Run Axe on:
- Storybook (or static fixtures) for each library component
- Key templates on CM preview and CD
- CI against a small URL list after each release
# Example: axe-core CLI against a staging URL list
npx @axe-core/cli https://staging.example.com/ --tags wcag2aa,wcag22aa
Lighthouse
Lighthouse accessibility category is a useful regression signal in CI. It is not a legal attestation. Treat a score drop as a stop-the-line for investigation, not as proof of AA compliance.
| Tool | Strength | Blind spot |
|---|---|---|
| Axe | Rules engine aligned to WCAG | Keyboard flows, screen reader verbosity, content sense |
| Lighthouse | Fast CI gate, trend charts | Incomplete rule set; false confidence from high scores |
| Manual keyboard | Real operability | Time; needs a scripted path |
| Screen reader (NVDA/VoiceOver) | Announcement quality | Requires trained testers |
| Sitecore field validation | Stops bad content at source | Does not replace front-end bugs |
Sitecore-Specific Failure Modes
| Failure | Where it starts | Library fix |
|---|---|---|
| Empty alt on images | Image field with blank Alt | Required Alt; reject publish in workflow if empty for informative images |
| "Click here" links | Rich text / General Link text | Author guide + optional RTE rules; QA grep |
| Carousel without pause | JS component default | Pause control required; prefer reduced-motion default |
| Focus outline removed | Global CSS outline: none | Tokenized :focus-visible styles in the design system |
| Modal focus trap broken | Custom JS | Use tested dialog pattern; restore focus on close |
| Skip link missing | Layout chrome | SkipLink as Foundation component on every page type |
| Sticky nav covers focus | CSS sticky + 2.2 focus not obscured | Scroll-margin / padding; test with keyboard |
Deep Dive: Encode Accessibility into Templates
Front-end fixes that authors can override are temporary. Put constraints in the CMS.
- Informative vs decorative images: Checkbox or droplink; decorative images force empty alt and
role="presentation"in the rendering. - Link text: Prefer General Link with explicit text; discourage RTE for primary CTAs.
- Headings: Component fields for H2/H3; do not let RTE invent random heading levels inside cards.
- Media: Video components require captions track or a transcript field before publish.
- Motion: Rendering parameter for autoplay defaulting to off; respect
prefers-reduced-motion.
// Pseudocode: refuse empty alt for informative images at render time (defense in depth)
if (model.ImageIsInformative && string.IsNullOrWhiteSpace(model.Alt))
{
// Log + show Experience Editor warning; do not emit <img> without alt
}
Deep Dive: Keyboard and Focus for Sitecore Chrome
Global and section navigation, HCP gates, cookie banners, and mega menus are where keyboard users get stuck.
- Tab order follows visual order (no positive
tabindexhacks). - Dropdowns use disclosure or menubar patterns from WAI-ARIA APG.
- Escape closes overlays; focus returns to the control that opened them.
- Focus visible styles stay clear for keyboard users; never remove outlines without a replacement. Sticky chrome must not fully hide the focused control (2.4.11).
- Sticky section nav uses
scroll-margin-topso focused headings are not hidden under the bar.
Deep Dive: Target Size and Touch
WCAG 2.2 AA (2.5.8) sets a 24×24 CSS px minimum target (or a spacing exception). That is the conformance floor, not the best UX. Icon-only social links, pager dots, and dense footer columns still fail on phones when hit areas stay tiny, so we treat 44×44 as the practical chrome bar (AAA 2.5.5 / common platform HIG).
| Pattern | Minimum practice |
|---|---|
| Icon buttons | 44×44 CSS hit area (clears the 24×24 AA floor); visible label or aria-label |
| In-page tabs | Adequate spacing; selected state not color-only |
| Carousel dots | Larger targets or provide prev/next buttons as primary |
| Cookie preferences | Large accept/reject controls; keyboard operable |
Pipeline: Where Tools Sit in Sitecore Delivery
- Design: Annotate focus, contrast, and motion in Figma/Zeplin.
- Component PR: Axe on Storybook stories; keyboard checklist attached.
- CM preview: Axe + manual pass on two page types.
- CD staging: Lighthouse CI + Axe URL list.
- Pre-prod: Screen reader sample on nav, forms, modal, media.
- Post-launch: Monthly Axe crawl; ticket backlog with severity.
# Playwright + axe example (sketch)
import { injectAxe, checkA11y } from 'axe-playwright';
await page.goto(url);
await injectAxe(page);
await checkA11y(page, null, { detailedReport: true });
What "Done" Looks Like for a Component
- Axe clean on Default / Active / Error / Mobile stories (known exceptions documented).
- Keyboard script passed and checked into the component folder.
- Contrast verified against design tokens (not one-off hex).
- CMS fields prevent the top authoring failures for that component.
- Reduced-motion behavior verified.
Further Reading
- WCAG 2.2 Recommendation
- How to Meet WCAG (Quick Reference)
- WAI-ARIA Authoring Practices Guide
- axe-core
- Lighthouse accessibility scoring
- Sitecore Experience Platform documentation (authoring)
Actionable Checklist
- Adopt WCAG 2.2 AA as the written acceptance bar in the component Definition of Done.
- Add Axe to Storybook/CI; track violation counts per release.
- Use Lighthouse as a regression signal, not a certificate.
- Require alt text and sensible link text at the template layer.
- Fix focus styles and sticky-header overlap (2.2 focus not obscured).
- Run keyboard + one screen reader pass on Global Nav, Section Nav, modals, and media before launch.
- Schedule a monthly accessibility crawl on production templates after go-live.