Repository navigation
fix(a11y): landmarks, names, focus order and contrast fixes from the accessibility scan - #53
Merged
Merged
Conversation
Wrap routed content in <main> in the layout, auth and error shells. Make the page title an h1 on the dashboard, table and cards pages (the NFT price in the dual card was the only h1, now h3). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add aria-label to icon-only buttons (sidebar toggle and submenu toggles, table row actions, pagination arrows, auction view buttons), to the table checkboxes, search input and filter, sort and page-size selects. Mark decorative icons aria-hidden, expose aria-expanded on the menu toggles and give the empty table headers screen reader text. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Closed sidebar submenus, the mobile menu and the top bar dropdowns were only hidden with max-height or opacity, so their links stayed focusable. Add visibility: hidden while closed (the transition keeps the animation working) and open the top bar dropdowns on :focus-within as well as hover so they remain usable from the keyboard. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add screen reader text to the three empty headers in the chart card table. The 'Showing 08 of 100 users' text on the table page is a status line, not a heading, so make it a paragraph. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Use the full muted-foreground colour instead of /50 and /70 opacity variants and text-gray-400 for text, darken the light theme muted-foreground token from #64748B to #4F5D75 so it also passes on the card and muted backgrounds, and use yellow-500 for the hobby badges in dark mode. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The sidebar toggle buttons now have accessible names, so the 'Auth' button name matched in both the sidebar and the navbar. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Use :has(:focus-visible) instead of :focus-within, so a mouse click on a trigger doesn't leave its menu open after the pointer leaves. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Its label already says whether it collapses or expands the sidebar. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
lannodev
approved these changes
Oct 19, 2026
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follows up on #52. This covers the findings from the scan of the demo (
/dashboard/nfts,/auth/sign-in,/components/table). Each fix is its own commit so you can take or drop them separately.What changed
<main>in the layout, auth and error shells, and the footer is now a<footer>. The page title is anh1on the dashboard, table and cards pages. The NFT price in the dual card was the onlyh1on the dashboard, so it is now anh3with the same classes. "Showing 08 of 100 users" is a<p>instead of anh3.aria-labelto the icon-only buttons (sidebar collapse, sidebar and mobile submenu toggles, table row actions, pagination arrows, auction "view" buttons), the table checkboxes, the search input and the status, sort and page-size selects. Decorative SVG icons inside them arearia-hidden="true". The submenu toggles and the mobile menu button also exposearia-expanded, which is whymenuServiceinnavbar.component.tsis nowpublic. The app has no i18n, so the labels are plain English strings like the rest of the templates.sr-onlytext to the five empty headers (select, actions, and the chart card's time, price and change columns).max-heightoropacityonly, so their links could still be tabbed to. They now also getvisibility: hiddenwhile closed (invisible), so the open and close animation still runs. The top bar dropdowns open on keyboard focus (.dropdown:has(:focus-visible)) as well as hover, so they can be used from the keyboard. A mouse click on a trigger does not keep the menu open. There is no Escape to close them yet, since they are opened by CSS only. The mobile panel'stransitionis nowtransition-[opacity,transform,visibility]so visibility changes after the fade.app-navbar.Contrast changes
text-muted-foreground/50or/70now usestext-muted-foreground(sidebar group titles, top bar items, footer, creator names, emails). Before: 1.97:1 light, 2.70:1 dark for/50; 2.71:1 light, 4.29:1 dark for/70. After: at least 6.08:1 light (on white or card), at least 7.43:1 dark (on the dark background or card).text-gray-400(2.60:1 on white). They now usetext-muted-foreground.--muted-foregroundgoes from#64748Bto#4F5D75. The old value was 4.34:1 on the card background and 3.33:1 on the muted background. The new value is 6.08:1 on card and 4.66:1 on muted (6.66:1 on white). The dark theme token is unchanged.text-muted-foregroundat rest, so their hover colour ishover:text-foregroundto keep a visible change on hover.dark:text-yellow-500on the dark theme. Before: 2.50:1. After: 8.94:1. The light theme is unchanged.Not changed: text in the primary colour (
#E11D48) on the dark background (4.21:1), the version badge (4.00:1 light, 3.98:1 dark) and the "Forgot your password?" link in dark mode (4.21:1). Fixing these means changing the brand colour or adding a separate text colour token, so I left that as your call. Icons attext-muted-foreground/50(the sidebar collapse button, menu icons, chevrons) are also unchanged.I also added
type="button"to the buttons I touched. None are in forms, so it only makes the intent explicit.How it was checked
An automated axe-core scan (via Playwright) of the three routes in light and dark mode, on
mainand on this branch, plus@ngbracket/a11y-devtoolsreport mode. Scripted keyboard checks with Playwright: Tabbing through the dashboard, opening and closing the sidebar submenus with Enter, opening the top bar dropdowns with focus, and checking a mouse click on a trigger doesn't leave the menu open. The existing Playwright e2e tests pass (8 of 8). No manual or screen reader testing was done.mainWhat is left: the contrast items above, the dev-only responsive helper badge (not rendered in production) and the decorative panel on the auth page, both reported by the
regionrule.ng lintis not configured in the repo andng testdoes not start onmain(/polyfills must be array), so those were not run.ng buildpasses.Follow-up
These came up while testing but are outside the scan findings, so they're not in this PR. Happy to open a follow-up PR for them if you'd like:
divs withrouterLinkandtabindex="0", but Enter doesn't activate them.divs orlis that can't be reached or used with the keyboard. The profile button has noaria-expanded.divs.href, so it isn't focusable.🤖 Generated with Claude Code