Accessibility-ready remediation - #4601
Conversation
60 tests in 8 spec files encoding the accessibility-ready acceptance criteria (see neve-pro-addon a11y.md / Trac #285870): - submenu keyboard/ARIA behavior incl. screen-reader activation path - focus visibility, tab order, stray tabindex - structure: single H1, duplicate IDs, landmark naming - form labels, link underline/hover/ambiguity - block pattern source lint + rendered checks - axe-core WCAG A/AA sweep over the reviewer's page types - skip link, prefers-reduced-motion, new-window warnings Own config (playwright.a11y.config.ts) running logged-out with no auth dependency; fixtures provisioned by bin/envs/a11y-ready (idempotent, reusable locally via WP-CLI); wired into the playwright.yml CI matrix as the a11y-ready env/spec pair, run via yarn test:a11y. Adds @axe-core/playwright dev dependency. Most tests fail against the unfixed theme by design (baseline 42 failed / 18 passed) — they describe the required end state and become the permanent regression gate once remediation lands. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replace the div[role=button] submenu toggles with native buttons that expose aria-expanded, unique labels, and a single click-driven open state — covering mouse, Enter, Space, and screen-reader activation with one code path. Add Escape-to-close with focus return, and close desktop submenus when focus leaves the item. Remove the Enter-only inline script, aria-pressed handling, and the .wrap.active CSS; fix the @extend cascade bug that kept .dropdown-open submenus invisible on desktop; replace the dead li:focus mega-menu selector with :focus-within. Move Nav_Walker's static inline CSS into the compiled stylesheet, which obsoletes Secondary_Nav_Walker's proxy hook (b757ea2). Raise the frontend.js size budget to 9 KB (baseline was already at ~8.04 KB; the ARIA/keyboard logic adds ~0.75 KB). Refs Trac #285870; closes #4539, keyboard part of #4425. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Remove every outline suppression (inputs, nav search item, hamburger, select2) so the browser-default focus ring shows on all interactive elements, and scope the .caret transition to transform/color — the bare shorthand meant 'all' and animated the focus ring in from zero width. Add tabindex="-1" to #content so the skip link genuinely moves focus. e2e: the focus-indicator helper now enforces the review's bar (default ring or >=2px outline; box-shadow glows no longer count) and a new sweep test Tabs through every interactive element on three fixture pages. Refs Trac #285870; focus-visibility part of #4425. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Palette: distinct darker/lighter hover accent (nv-secondary-accent was identical to the primary, so hover states changed nothing); nv-c-1/nv-c-2 deepened past their borderline 4.51:1; dark-mode equivalents fixed too. Forms: border #dddddd -> #8c8c8c (>=3:1 on both backgrounds), placeholder opacity 0.5 -> 0.7 (>=4.5:1), search submit label no longer uses the border color as text color. Buttons: hover defaults now differ from rest (fill darkens, outline fills with the light background); the global a:hover accent no longer clobbers button-like links' text color (it put a dark accent on core's dark button background). Links: underline drops on hover as the non-color cue; classed prose links are underlined too. Pagination: hover/focus style, screen-reader 'Page N' names, labelled nav wrapper. Nav carets: 24px minimum touch target (WCAG 2.5.8). Adds an a11y-w3-showcase fixture page for visual review. All 7 axe scans and the whole links spec now pass (suite 24 failed / 37 passed, zero regressions). Refs Trac #285870. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Buttons get href attributes (keyboard reachable); every pattern image gets alt text — the text-as-image transcribed, team portraits named, standalone photos described, gallery thumbs generic; the two pattern H1s become H2s; headings added where the review asked (team members, gallery grid) and first-heading H3s promoted so patterns start at H2; the three identical LEARN MORE links get distinct names. Also removes a duplicate three-columns-images-text registration in patterns.php. Refs Trac #285870. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Featured images on the archive posts and a footer-menu component on both desktop and mobile builder rows — without these, the thumbnail-link tests and the duplicate-id/footer-landmark tests passed vacuously (nothing rendered to check). Suite baseline moves 10 -> 14 failed, all W5/W6 scope. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ready Headings: 404 gets an H1; hidden page/archive titles render as a screen-reader-only H1 instead of disappearing. Forms: search input gets an associated label (visible on the 404/no-results forms), decorative search/close SVGs are aria-hidden. Landmarks: the header row wrapper is a div (no nav-in-nav), menu landmarks are named per device, footer menu ids are unique per device (closes #4557), sidebars get unique ids and labels. Controls: search trigger and palette switch are real buttons with aria-expanded/aria-pressed state, the hamburger has one naming source, the logo aria-label no longer overrides a visible title, thumbnail links lose the title attr and gain the post title as their name, comment links carry SR-only post context. Keyboard order: excerpt tabindex removed; scroll-to-top renders after the footer, and its focus() no longer cancels its own smooth scroll (regression from tabindex=-1 on #content); palette button inherits color (icon was white-on-white in light mode). e2e: scroll-to-top completion regression test; search-form specs scoped to the content area; fixtures render search/palette/secondary-menu so their coverage is not vacuous. frontend.js budget 9 -> 9.25 KB. Refs Trac #285870; closes #4557. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- scroll-to-top jumps instantly when prefers-reduced-motion is set - HFG Button component appends a screen-reader-only '(opens in a new tab)' warning when open-in-new-tab is enabled (reuses existing string) - a11y fixtures render a new-tab Button so the warning test isn't vacuous Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The mega menu reveal no longer uses :focus-within, which kept the panel painted after its toggle closed it while focus remained on the toggle — Escape now actually hides the panel. The shared focus trap in navigation.js gains a per-trap onClose so Escape on the header search closes the panel instead of the menu sidebar, returns focus to the trigger button (backFocus was an unfocusable div, dropping focus to body), and the trap ends on every close path (trigger re-click, close button, click-away overlay) instead of going stale and swallowing Tab. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…itch target size The off-canvas cart drawer is now a real modal dialog: the template renders role=dialog/aria-modal/aria-label, an initial inert attribute, a real Close button instead of an href=# link, and aria-haspopup + aria-expanded on the opener (which stays a plain link to the cart page as the no-JS fallback). The hover/:focus-within mini-cart reveal excludes the drawer so focusing the cart icon can no longer slide it open (WCAG 3.2.1). should_load_pro_features() additionally requires Sparks, mirroring the booster's own should_load(), so a saved off-canvas mod falls back to the dropdown mini-cart when the feature cannot actually run instead of leaving a dead drawer with no Customizer control to undo it. Mega menu column lists switch to visibility:inherit so links inside a closed panel are no longer focusable off-screen. The palette switch toggle gets a 24x24 minimum hit area (WCAG 2.5.8); it rendered at 16x16 (the icon size) at every viewport. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Primary nav instances from pro (primary-menu_2/_3) rendered identical landmark labels; the nav template now numbers them the way the customizer does (Primary Menu 1 (Desktop)) and keeps the ul id unique when two instances share a row. The unique-toggle-names spec asserts uniqueness per navigation landmark, since the same menu may legitimately render in several labelled navs. Menu dividers (legacy title convention or the pro mega menu's contentType class) render as aria-hidden empty list items instead of role=presentation, which axe's list rule rejects as a direct ul child. The responsive search panel drops its untranslatable aria-label on a role-less div — the form inside is the real search landmark — with a regression check in the forms spec. The dropdown mini cart's cart-dropdown-open reveal moved out of the mobile media query so the pro booster's auto-expand (and any width) can open it by class; the base element is display:none, which inline styles never could override. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The new-tab indicator echo folds into a single wrapped line so the embedded-php tag sniffs pass without introducing whitespace inside the button text, and both output branches run through wp_kses_post. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
the_title_attribute()'s array shape only accepts a WP_Post for 'post', so the thumbnail link's aria-label now builds the same escaped title via get_the_title() with the resolved post id. The modern frontend.js bundle grew past the 9.25KB budget with the accessibility disclosure work; raise it to 9.5KB to match the built size (9.43KB), same as the earlier 8KB -> 9.25KB bump on this branch. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Brings in the Theme Check fixes shipped on development (WordPress spelling, themeisle-sdk 3.3.60, dist-zip excludes for composer installed.json and the SDK changelog) plus the fixes since the branch was cut. Conflict resolution: the primary menu id now uses development's Nav::get_menu_id() (device + row) with this branch's pro-instance suffix on top, and the footer menu id takes development's device + row form. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The breadcrumb links were distinguished from the surrounding crumb text only by the palette link color (1.69:1 on defaults) — axe link-in-text-block, WCAG 1.4.1. Underline them like content links. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Users who ask the OS for reduced motion now get instant show/hide on the significant movement: the mobile menu sidebar slide and the page shift it causes (.wrapper/.tcb/.hfg-ov) and the Woo off-canvas filter sidebar. Opacity-only fades stay. .screen-reader-text adopts core's clip pattern (clip-path inset(50%), word-wrap normal — the legacy left:-10000px variant can force RTL horizontal scroll) and gains the :focus reveal so plugin skip links on this class become visible when focused. Also carries the .nv-hover-off rule that navigation.js (next commit) drives to make hover-opened submenus Escape-dismissable, covering the pro submenu animation flavors via !important. Size budgets: style-main-new 40 -> 40.5 KB, frontend.js 9.5 -> 9.75 KB. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Submenus revealed by pure CSS :hover had no dismissal mechanism — content that obscures the page must be dismissable without moving the pointer. Escape now sets body.nv-hover-off (the stylesheet hides li:hover > .sub-menu under it, keyboard-opened .dropdown-open panels excluded); the pointer leaving the hovered item re-arms hover. New e2e regression: hover-open -> Escape dismisses with the pointer parked -> re-hover re-opens. Verified against all three submenu flavors including the pro slide/fade animations. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Classic navigation-type widgets (Pages, Categories, Archives, Nav Menu…) now render wrapped in labeled nav landmarks instead of bare lists. Part of the W5 landmarks scope that never landed; block widgets are unaffected (verified byte-identical output), and the only change for classic widgets is the nav wrapper — no theme CSS targets it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
accessibility.txt (theme root, ships in the dist zip) documents the
accessibility statement, audit status, testing methodology, the
screen-reader-text class, features, and where to get help or report
issues — the sections the accessibility-ready review requires since
June 2026.
Metadata drift fixed: Tested up to 6.2/6.4 -> 7.1 in style.css and
readme.txt, the plugin-ism 'Stable tag: trunk' removed, tag lists made
identical (block-patterns added to style.css; custom-header and
flexible-header removed everywhere — the theme has no
add_theme_support('custom-header'); featured-image-header stays, the
cover header uses the featured image). readme.md regenerated.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The footer copyright component renders its credit links inside a sentence with no visual distinction from the surrounding text — same color, same weight, no underline. Links in text must not rely on color alone, so the copyright component's anchors now carry an explicit underline. Footer menu links are unaffected (navigation is exempt). Found during the close-out visual comparison against a pre-remediation development install; present there too, so this was a pre-existing gap rather than a regression. Adds a links.spec regression test; suite now 65 tests, style-main-new.min.css at 40.46KB of the 40.5KB budget. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
🌍 i18n String Review Report📊 Summary
➕ Added Strings (3) - Click to expand
➖ Removed Strings (1) - Click to expand
|
abaicus
left a comment
There was a problem hiding this comment.
@HardeepAsrani Looks fine, I couldn't spot much. We can also run a copilot review on the PR and make sure the tests pass before merging.
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Introduces a broad accessibility remediation pass aimed at meeting WordPress.org “accessibility-ready” re-review expectations, and adds a dedicated Playwright-based acceptance suite (including axe-core) to prevent regressions.
Changes:
- Updates theme markup/ARIA for landmarks, navigation toggles, sidebars, search forms, pagination, and headings (unique IDs/names, correct roles/states, visible labels where required).
- Adds a new “a11y-ready” Playwright acceptance suite (plus fixtures + CI matrix entry) and integrates axe-core scans.
- Improves accessibility-related styling/behavior (focus visibility, reduced-motion handling, link affordances/hover states, contrast-related defaults).
Reviewed changes
Copilot reviewed 80 out of 83 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| yarn.lock | Locks new dev dependency (@axe-core/playwright) and related resolution changes. |
| package.json | Adds @axe-core/playwright and a dedicated test:a11y script; updates bundle size thresholds. |
| views/sidebar.php | Makes sidebar IDs unique per position and adds an aria-label for the complementary landmark. |
| views/page-header.php | Ensures an H1 exists even when titles are visually hidden (screen-reader-only). |
| style.css | Updates “Tested up to” and tags to reflect newer WP version and block-pattern support. |
| sidebar.php | Fixes duplicate sidebar IDs and labels the complementary landmark. |
| sidebar-shop.php | Fixes duplicate sidebar IDs and labels the complementary landmark. |
| searchform.php | Correctly associates <label for> with the search input and supports a visible label mode. |
| readme.txt | Updates tags formatting and bumps “Tested up to” version. |
| readme.md | Updates tags formatting and bumps “Tested up to” version. |
| inc/views/template_parts.php | Removes redundant title attribute and uses aria-label for thumbnail links to avoid double announcements. |
| inc/views/secondary_nav_walker.php | Documents why the constructor intentionally does not call the parent. |
| inc/views/scroll_to_top.php | Moves scroll-to-top button later in DOM order and adjusts button markup. |
| inc/views/pluggable/pagination.php | Adds accessible pagination context (“Page N”) and wraps pagination in a labeled nav landmark. |
| inc/views/partials/post_meta.php | Disambiguates comment-count link names with SR-only post context. |
| inc/views/partials/excerpt.php | Removes stray tabindex from non-interactive excerpt wrapper. |
| inc/views/nav_walker.php | Refactors submenu toggles to native buttons with aria-expanded and a single shared open state; improves divider semantics. |
| inc/views/layouts/layout_sidebar.php | Derives a human-readable sidebar label from registered sidebars for aria-label usage. |
| inc/views/header.php | Converts header search trigger/close to buttons and adds aria-expanded handling hooks. |
| inc/views/content_none.php | Requests visible search labels for no-results contexts. |
| inc/views/content_404.php | Adds a visible H1 and requests visible search labels for 404 contexts. |
| inc/customizer/options/form_fields.php | Improves default form border color for contrast. |
| inc/core/styles/frontend.php | Updates default CSS variable for form field border color. |
| inc/core/front_end.php | Enables navigation-widgets HTML5 support. |
| inc/compatibility/patterns.php | Removes a duplicate pattern registration entry. |
| inc/compatibility/block-patterns/two-columns-image-text.php | Adds meaningful alt text, fixes heading markup, and adds href for button-like links. |
| inc/compatibility/block-patterns/two-columns-centered-content.php | Adds meaningful alt text and corrects headings to avoid H1 / improve structure. |
| inc/compatibility/block-patterns/three-columns-images-texts-content.php | Adds meaningful alt text, adjusts heading levels, and fixes href-less links. |
| inc/compatibility/block-patterns/three-columns-images-text.php | Adds meaningful alt text and adjusts headings to avoid invalid H1 usage. |
| inc/compatibility/block-patterns/testimonials-columns.php | Adds descriptive alt text for testimonial avatar images. |
| inc/compatibility/block-patterns/light-header-left-aligned-content.php | Adds meaningful alt text, avoids H1 in pattern content, and fixes href-less links. |
| inc/compatibility/block-patterns/gallery-title-buttons.php | Adds alt text for gallery images and fixes href-less links. |
| inc/compatibility/block-patterns/gallery-grid-buttons.php | Adds a heading for structure, adds alt text, and fixes href-less links. |
| inc/compatibility/block-patterns/four-columns-team-members.php | Adds section heading and descriptive alt text for team member images. |
| inc/compatibility/block-patterns/dark-header-centered-content.php | Avoids H1 in pattern content and fixes href-less links. |
| header.php | Makes the skip-link target focusable via tabindex=-1. |
| header-footer-grid/templates/row-wrapper-mobile.php | Removes redundant aria-label/value to rely on a single naming source for the menu toggle. |
| header-footer-grid/templates/row-wrapper-main.php | Prevents nested navigation landmarks by changing the wrapper from <nav> to <div>. |
| header-footer-grid/templates/components/component-search-responsive.php | Removes stray aria-label on generic div and hides decorative SVG from AT. |
| header-footer-grid/templates/components/component-palette-switch.php | Uses a button element and adds aria-pressed for the palette toggle. |
| header-footer-grid/templates/components/component-nav.php | Ensures repeated navigation landmarks have unique accessible names and unique menu IDs per instance and device. |
| header-footer-grid/templates/components/component-nav-secondary.php | Ensures secondary nav landmark names are unique per device. |
| header-footer-grid/templates/components/component-nav-footer.php | Ensures footer nav landmark names are unique per device. |
| header-footer-grid/templates/components/component-menu-icon.php | Avoids duplicate naming sources and conditionally adds aria-label only when needed. |
| header-footer-grid/templates/components/component-logo.php | Avoids unnecessary aria-label overrides when visible branding text already names the element. |
| header-footer-grid/templates/components/component-cart-icon.php | Improves off-canvas cart semantics (dialog attrs, inert) and converts close control to a button. |
| header-footer-grid/templates/components/component-button.php | Adds SR-only warning text for links that open in a new tab. |
| header-footer-grid/Core/Components/PaletteSwitch.php | Updates CSS for button-based toggle and syncs aria-pressed state via JS. |
| header-footer-grid/Core/Components/CartIcon.php | Avoids rendering pro-only cart markup when required dependency (Sparks) is not present. |
| globals/utilities.php | Makes search icon decorative (aria-hidden), converts trigger to button semantics, and adjusts default palette colors for contrast/hover affordance. |
| globals/migrations.php | Improves default button hover affordances (non-color-only cues and contrast-friendly hover colors). |
| e2e-tests/specs/a11y-ready/submenu-keyboard.spec.ts | Adds desktop/mobile submenu toggle keyboard/state/name tests including NVDA activation path. |
| e2e-tests/specs/a11y-ready/structure.spec.ts | Adds landmark naming/uniqueness, duplicate ID, and heading structure tests. |
| e2e-tests/specs/a11y-ready/patterns.spec.ts | Adds block pattern source lint + rendered checks for href-less links, empty alts, and H1 usage. |
| e2e-tests/specs/a11y-ready/motion-context-window.spec.ts | Adds skip-link focus behavior, reduced-motion scroll-to-top, and new-tab warning/rel checks. |
| e2e-tests/specs/a11y-ready/links.spec.ts | Adds tests for underlines, hover non-color changes, pagination naming, and thumbnail link announcements. |
| e2e-tests/specs/a11y-ready/forms.spec.ts | Adds tests for visible persistent labels and decorative SVG aria-hidden requirements. |
| e2e-tests/specs/a11y-ready/focus-visibility.spec.ts | Adds focus indicator coverage and tab order regression tests. |
| e2e-tests/specs/a11y-ready/axe.spec.ts | Adds automated axe-core WCAG A/AA sweep gate for key page types. |
| e2e-tests/specs/a11y-ready/a11y-utils.ts | Adds shared helpers for permalink resolution, accessible name collection, focus indicator checks, and duplicate ID detection. |
| e2e-tests/specs/a11y-ready/README.md | Documents the acceptance suite intent, fixtures, and how to run locally/CI. |
| e2e-tests/playwright.a11y.config.ts | New Playwright config for the dedicated a11y suite (logged-out, baseURL driven). |
| bin/envs/a11y-ready/start.sh | Adds a CI environment entry to provision the a11y-ready fixtures. |
| bin/envs/a11y-ready/fixtures.sh | Adds deterministic WP-CLI fixtures required by the a11y acceptance suite. |
| assets/scss/elements/_mega-menu.scss | Aligns mega menu open state with .dropdown-open instead of impossible li:focus. |
| assets/scss/components/main/_typography.scss | Improves link hover affordances with non-color cues and avoids breaking button-like links. |
| assets/scss/components/main/_a11y.scss | Updates .screen-reader-text to core-like clip pattern, adds hover-dismiss support, and reduced-motion transitions. |
| assets/scss/components/hfg/frontend/layout/_footer.scss | Ensures footer copyright links are underlined (non-color-only). |
| assets/scss/components/elements/navigation/_nav-toggle.scss | Removes custom focus outline override to rely on UA focus ring. |
| assets/scss/components/elements/navigation/_nav-search.scss | Removes outline suppression and strips UA button styling for search triggers. |
| assets/scss/components/elements/navigation/_nav-menu.scss | Avoids animating focus outline; adds .dropdown-open submenu open state and button caret styling. |
| assets/scss/components/elements/form-elements/_inputs.scss | Stops suppressing outlines; improves placeholder contrast. |
| assets/scss/components/elements/blog/_pagination.scss | Adds visible hover/focus styling for pagination links. |
| assets/scss/components/elements/_mega-menu.scss | Aligns mega menu open state with .dropdown-open and fixes visibility inheritance to avoid tabbable hidden links. |
| assets/scss/components/elements/_form-elements.scss | Supports visible search labels layout and improves search button text contrast. |
| assets/scss/components/compat/woocommerce/_sidebar.scss | Disables sidebar transitions for reduced-motion users. |
| assets/scss/components/compat/woocommerce/_nav-cart.scss | Fixes cart dropdown reveal logic across widths and prevents dialog opening on focus. |
| assets/scss/components/compat/woocommerce/_checkout.scss | Stops suppressing outline on open select2 container. |
| assets/scss/components/compat/woocommerce/_breadcrumbs.scss | Underlines breadcrumb links to avoid color-only distinction. |
| assets/js/src/scroll-to-top.js | Honors prefers-reduced-motion, prevents focus() from canceling smooth scroll, and removes redundant keydown handler. |
| assets/js/src/frontend/navigation.js | Unifies submenu toggle logic around native buttons, aria-expanded, overlay close behavior, Escape handling, and focus trap close hooks. |
| accessibility.txt | Adds an accessibility statement describing targets, testing methodology, and support/issue reporting paths. |
| .github/workflows/playwright.yml | Adds an “a11y-ready” matrix entry and runs the new test:a11y suite in CI. |
Suppressed comments (3)
inc/views/scroll_to_top.php:1
- When AMP is enabled,
$ampis a full attribute string (on=\"...\") and escaping it withesc_attr()will turn quotes into", producing malformed markup (and it’s also concatenated without a leading space). Build a proper attribute fragment that includes a leading space and only escape the attribute value (or output the hardcoded AMP attribute withoutesc_attr()since it’s not user input).
globals/utilities.php:1 - The search button’s
aria-labelis built with__()inside an HTML attribute; translations can include characters that need attribute-escaping, so this should useesc_attr__()(or wrap withesc_attr()). Also,$amp_statestill injectsrole=\"button\"even when the wrapper is now a native<button>, which is redundant and can trigger ARIA validator/axe noise—consider only addingrole=\"button\"when the wrapper is a non-button element.
globals/utilities.php:1 - The search button’s
aria-labelis built with__()inside an HTML attribute; translations can include characters that need attribute-escaping, so this should useesc_attr__()(or wrap withesc_attr()). Also,$amp_statestill injectsrole=\"button\"even when the wrapper is now a native<button>, which is redundant and can trigger ARIA validator/axe noise—consider only addingrole=\"button\"when the wrapper is a non-button element.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
The copyright underline shipped against .builder-item--footer_copyright, a Pro-only component class — the free theme renders the credit as .builder-item.cr, so the rule and its regression test matched nothing on CI. Both now cover the free and Pro markup. Also adds core's legacy clip: rect(1px,1px,1px,1px) fallback to .screen-reader-text per Copilot review, with the matching clip: auto reset on :focus so skip links still reveal. CSS budget raised 40.5 → 40.6 KB for the added rules (built size 41508 bytes). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Summary
Remediation of every finding from the WordPress.org
accessibility-readyreview (Trac #285870, tracked in Codeinwp/neve-pro-addon#3240), plus a self-audit against the current theme accessibility guidelines. All 18 guidelines are covered; the work is verified by a new dedicated e2e suite (65 tests, wired into the existing Playwright CI matrix) and by manual keyboard + VoiceOver passes.Navigation & disclosure
<button>elements witharia-expanded, unique accessible names ("{item} submenu"), andaria-controlspointing at id-stamped submenu<ul>s; Enter/Space/Escape all work, Escape returns focus to the toggle.onCloseand reliable teardown (a stale trap used to swallow Tab).Focus & contrast
outline: noneremovals fixed; default ring or ≥2px outline).nv-c-1/nv-c-2, form borders, placeholders, button hovers) — same hues, darkened to pass; sites with customized colors are untouched.Structure, landmarks, forms
navigation-widgetshtml5 support.aria-hidden; search trigger/palette switch/hamburger are proper buttons with synced state; 24px minimum targets (carets, palette switch).Motion & context
prefers-reduced-motionhonored (scroll-to-top, sidebar/overlay transitions, Woo filter sidebar); "(opens in a new tab)" screen-reader text on new-tab links; off-canvas cart falls back to the dropdown mini-cart when the pro booster can't run, and focus alone never opens it..screen-reader-textupgraded to the core clip pattern with a:focusreveal, documented in the newaccessibility.txt(all 7 sections per the wpaccessibility.org standard).Testing infrastructure
e2e-tests/specs/a11y-ready/suite (65 tests) behindplaywright.a11y.config.tswith its owna11y-readyfixture env (bin/envs/a11y-ready/fixtures.sh), including axe-core WCAG A/AA scans on 7 page types. Already added to theplaywright.ymlmatrix, so it gates CI from the first merged commit. Size budgets updated: frontend.js 9.75 KB, style-main-new.min.css 40.5 KB.How this was tested
Every finding went through four independent passes, both before the fix (to reproduce the broken state) and after it (to confirm the remediation):
Finally, the branch was compared page-by-page and component-by-component (paired screenshots, desktop + mobile) against a pre-remediation
developmentinstall to confirm no unintended visual regressions.Will affect visual aspect of the product
YES — intentional, minimal: slightly darker default accent/palette colors and form borders (contrast), underlined prose links, visible focus rings, 24px caret/palette-switch targets. Sites with customized colors keep their saved values.
Test instructions
Check before Pull Request is ready:
Closes #4557.
Part of Codeinwp/neve-pro-addon#3240 (Trac #285870).
🤖 Generated with Claude Code