Observed
In an app with no Button.label locale token registered (the framework builder), screen readers announce "Button.label" — the raw locale key — as the accessible name on Button.Root usages across the app, per the Chromium accessibility tree. Affected examples include icon-only buttons (remove-token X) and, notably, buttons with visible text ("Start configuring", "Save & Next", "Open in Playground"), where the bogus aria-label overrides the visible text name.
Mechanism
ButtonRoot.vue:217:
'aria-label': ariaLabel || (isSolo.value ? locale.t('Button.label') : undefined),
useLocale/adapters/v0.ts:46 — t() returns the key verbatim when unregistered, so the fallback is the literal string Button.label.
- No locale bundle in the repo defines
Button.label, so every consumer that doesn't register it ships the raw key.
This is the same class of gap as #196 (components should coalesce to an English default when t() returns the key verbatim — PHILOSOPHY §5.5) but on the aria-label path. Additionally, isSolo appears to be true for renderless usages that clearly have text content, which makes the override land on text buttons too — that detection deserves its own look while in there.
Proposed fix
Two layers, consistent with §5.5:
- Never emit a raw key: coalesce
locale.t('Button.label') to an English default (or emit no aria-label at all) when the lookup returns the key verbatim.
- Don't set a fallback aria-label when the button has visible text content — per WCAG, aria-label should not override a usable visible name. Restrict the fallback to genuinely icon-only buttons, and verify why
isSolo is true for renderless text-bearing usages.
Regression tests next to the existing aria coverage at packages/0/src/components/Button/index.test.ts:602-627:
- solo button without explicit
ariaLabel must not expose aria-label="Button.label"
- button with visible text must not get any default aria-label
Observed
In an app with no
Button.labellocale token registered (the framework builder), screen readers announce "Button.label" — the raw locale key — as the accessible name on Button.Root usages across the app, per the Chromium accessibility tree. Affected examples include icon-only buttons (remove-token X) and, notably, buttons with visible text ("Start configuring", "Save & Next", "Open in Playground"), where the bogus aria-label overrides the visible text name.Mechanism
ButtonRoot.vue:217:useLocale/adapters/v0.ts:46—t()returns the key verbatim when unregistered, so the fallback is the literal stringButton.label.Button.label, so every consumer that doesn't register it ships the raw key.This is the same class of gap as #196 (components should coalesce to an English default when
t()returns the key verbatim — PHILOSOPHY §5.5) but on the aria-label path. Additionally,isSoloappears to be true for renderless usages that clearly have text content, which makes the override land on text buttons too — that detection deserves its own look while in there.Proposed fix
Two layers, consistent with §5.5:
locale.t('Button.label')to an English default (or emit no aria-label at all) when the lookup returns the key verbatim.isSolois true for renderless text-bearing usages.Regression tests next to the existing aria coverage at
packages/0/src/components/Button/index.test.ts:602-627:ariaLabelmust not exposearia-label="Button.label"