Repository navigation
a11y(wallet): give icon-only buttons an accessible name - #12
Merged
Miracle656 merged 2 commits intoSep 6, 2026
Merged
Conversation
Fifteen icon-only buttons announced as bare "button" to a screen reader.
Seven had a title tooltip but no accessible name; eight had neither.
Labelled: dashboard copy-address and its two dismiss buttons, the NFT
refresh and detail close, agent clear-history and back, contacts delete,
multisig remove-signer, the install banner dismiss, the contact picker
close, and the back arrows on settings/agent, settings/profile and
token/[code].
Labels follow the vocabulary already in the tree ("Back to settings",
"Back") rather than a new one. The two dashboard dismiss buttons, both
titled "Dismiss", get distinct labels so they are told apart out of
context. The agent toggle also picks up role="switch" and aria-checked to
match the Toggle in components/ui/primitives.tsx, which is the existing
house pattern for a switch.
Additive only: 18 lines, all ARIA attributes, no style, layout or copy
changed. Buttons whose label is rendered text were left alone.
Two of the labels added here replaced a visible label rather than supplying a missing one, which is the case WCAG 2.5.3 (Label in Name) covers: a speech-input user says what they can see, so the accessible name has to contain it. The dashboard copy button is not icon-only — it renders the truncated address, and the dashboard is the only place that address appears. A bare "Copy wallet address" said what the button does but took the address away from screen reader users entirely. The label now carries both. The agent toggle sits beside a visible "Veil Agent" heading, so that is its name; role="switch" and aria-checked already announce the on/off state, which "Enable AI agent" was duplicating in words and, when the switch was already on, contradicting. Claude-Session: https://claude.ai/code/session_01USgemLt4Rnz4SGB1Srf3GB
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.
Closes #4
What changed: Gave an accessible name to the 15 icon-only buttons in the wallet that had none. 18 added lines, all ARIA attributes, across 10 files. Nothing removed.
Why: These announced as a bare "button" to a screen reader. Seven had a
titletooltip, which is unreliable as an accessible name and invisible on touch; eight had neither.Copy wallet addressDismiss fee-payer warningDismiss stranded balance noticeRefresh NFTsClose NFT detailsClear historyBackDelete contactRemove signerDismiss install promptClose contact pickerBack to settingsBackEnable AI agentThree notes on the choices:
Back to settingsappears 4× andBackonce, so the back arrows follow that rather than a new phrasing.Dismiss. They sit on the same screen, so identical names are ambiguous out of context; theiraria-labels distinguish them while the visible tooltips stay as they were.role="switch"andaria-checked, matching theToggleincomponents/ui/primitives.tsx, which is the existing house pattern for a switch. Without a role it announced as a button with no state.type="button"came along from that same pattern; it is a no-op here, there is no<form>in the file.What I deliberately left alone: buttons whose accessible name is already rendered text. I scanned all 228
<button>elements underapp/andcomponents/and classified them; the ones that look icon-only but are not (nftsdev-mode toggles, theCopy/Copiedbutton,NetworkSwitcher) all render a visible label. The settings gear inTabBar/AppShellis likewise already correct: visible text label witharia-hiddenon the glyph.How tested:
npm run typecheckinfrontend/walletclean.npm run buildsucceeds, all routes compile.npm test: 251 passed. One suite,feeBump.test.ts, fails to load onReferenceError: TextEncoder is not defined. That is pre-existing onmainand unrelated to this change; it is fixed separately in test(wallet): cover truncateAddress edge cases #11.aria-label.Not tested: I did not verify with a screen reader or the a11y devtools pane, so that acceptance box is unticked from my side. There is no
eslint-plugin-jsx-a11yin the project and no component-render test setup (@testing-library/*is not installed), so I had no way to assert computed accessible names automatically without adding a dependency, which felt out of scope here. Worth a real screen-reader pass before merge, particularly on therole="switch"toggle.Notes:
npm run lintinfrontend/walletis broken onmain, unrelated to this change: the script isnext lint, which Next 16 removed, so it fails withInvalid project directory provided, no such directory: .../lint. There is also no eslint config in that package. Happy to send a follow-up migrating it toeslintdirectly, and addingeslint-plugin-jsx-a11ywould make regressions like this issue fail CI rather than needing a manual audit.Note also that
frontend/wallet's jest suite is not run by CI at all (only thesdkandmobilejobs invoke tests), so nothing here is currently enforced automatically.