Repository navigation
fix(Typeahead): the value token's button is named by the field label and the value - #9049
Conversation
…and the value (WCAG 2.4.6, 4.1.2)
With a value, Typeahead takes its input out of the Tab order, so the
Tab stop is the token's inner button, and that button was named by the
value alone ("Apple, button"), with no field name, description or
status. It is now labelled by the field label and the value and
described like the input. A clickable Token passes aria-labelledby and
aria-describedby to the inner button that owns its action
(public-component-api INV5) instead of the generic root. Fixes #8945.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
PR Analysis Report
📚 Storybook Preview🧪 Sandbox PreviewModified ComponentsToken (@astryxdesign/core) · View in Storybook
Component Size
Sizes are gzip. Import counts the JavaScript the import loads eagerly; CSS counts the package stylesheet rules referenced by the modules it can load from its own package, lazily loaded ones included. Bundle Size SummaryGzip figures measure each package's entry file, not the code an import pulls in.
Accessibility AuditStatus: The accessibility audit did not run on this pull request. It runs after merges to Generated by PR Enrichment workflow | Storybook | Sandbox | View full report |
|
AI review status for this pull request.
|
There was a problem hiding this comment.
The standalone naming works in Chromium, but approval waits on a spec decision: this change sends a clickable Token's aria-labelledby and aria-describedby to its inner button, while Token.spec.md FR10 and AR2 still say ARIA props reach the root and that the inner button is named by its label. An engineering owner needs to either amend those claims in this pull request, recording it by commenting /approve-spec <full head SHA> (the author may do so if they are an engineering owner), or keep root routing, in which case the Typeahead needs another way to name its token.
- Inside an
InputGroupthe token is named "Selection Apple" while its combobox is "Favorite fruit Selection"; labelling it with the input's grouped ids atTypeahead.tsx:672, with a grouped test, keeps the group label. - The changeset should name the accessibility target (WCAG 2.2 SC 1.3.1 and 2.4.6) and the Token's old behavior.
[Automated review]
| size={size} | ||
| onClick={handleEnterEditMode} | ||
| isDisabled={isDisabled} | ||
| aria-labelledby={`${inputGroup ? inputLabelId : fieldLabelId} ${tokenValueId}`} |
There was a problem hiding this comment.
Inside an InputGroup this labels the token with the Typeahead's own hidden label and the value. The combobox it replaces as the Tab stop is labelled by the group label plus that label (getInputARIA), so the grouped Tab stop reads "Selection Apple" where the combobox reads "Favorite fruit Selection". Using the input's ids when grouped keeps the group label:
aria-labelledby={`${inputGroup ? ariaLabelledBy : fieldLabelId} ${tokenValueId}`}| <button | ||
| type="button" | ||
| onClick={effectiveOnClick} | ||
| {...labellingProps} |
There was a problem hiding this comment.
Token.spec.md FR10 still says supported ARIA props reach the root, and AR2 says the clickable inner button takes its name from its label. This routing needs those claims amended in this pull request, or an owner decision to keep root routing, before it can land.
| '@astryxdesign/core': patch | ||
| --- | ||
|
|
||
| [fix] With a value, a `Typeahead`'s Tab stop is the value's token button, and it is now named by the field label and the value ("Fruit Apple", not just "Apple") and described by the field's description and status, so screen reader users know which field it belongs to. A clickable `Token` now passes `aria-labelledby` and `aria-describedby` to its inner button. |
There was a problem hiding this comment.
spec:AST-017 FR53 asks a patch accessibility fix's changeset to name the accessibility target it serves (for example WCAG 2.2 SC 1.3.1 and 2.4.6) and the old behavior, which for Token is the props landing on the root span.
Main's #8862 fix names the input with the field label plus a caller aria-labelledby, and sets Field's labelID only for that case. The value token's button now takes the same name plus the value (with a test), and labelID is always set because the token references the field label. Token tests keep both sides.
There was a problem hiding this comment.
Approval waits on a spec decision: a clickable Token now sends aria-labelledby and aria-describedby to its inner button, but Token.spec.md FR10 and AR2 still say ARIA props reach the root and that the inner button is named by its label. An engineering owner needs to either amend those claims in this pull request, recording the decision by commenting /approve-spec <full head SHA> (the author may do so as an engineering owner), or keep root routing, in which case the Typeahead needs another way to name its token. Two fixes are needed either way:
- A disabled link
Token(hrefwithisDisabledand noonRemove) no longer renders a caller'saria-labelledbyoraria-describedby, because that branch does not spreadlabellingProps. - The changeset should name the WCAG criteria it serves (for example 2.4.6 and 4.1.2) and Token's old behavior, as
spec:AST-017FR53 asks.
The Typeahead naming itself works: the Tab stop reads "Fruit Apple", and "Favorite fruit Selection Apple" inside an InputGroup.
[Automated review]
| 'aria-labelledby': ariaLabelledBy, | ||
| 'aria-describedby': ariaDescribedBy, |
There was a problem hiding this comment.
These two props now leave rest, but the disabled link branch (href with isDisabled and no onRemove, lines 373-397) spreads only rest and sharedProps, so a disabled link token renders neither: Chromium names it by its label instead of the caller's aria-labelledby and drops the description. Spreading {...labellingProps} after {...rest} there keeps them on the root, as Token.spec.md FR10 requires, and a Token test over every structure would catch it.
… AR2 say where clickable naming goes; changeset names old behavior and WCAG Review follow-up: aria-labelledby and aria-describedby left rest, and the disabled link branch spread only rest, so a disabled link token dropped them; it now spreads labellingProps on its root, with a test. Token FR10 and AR2 record that a clickable token's naming inputs reach its inner button (public-component-api INV5), and the FR10 verification row checks it. The changeset names Token's old routing and WCAG 2.4.6 and 4.1.2.
There was a problem hiding this comment.
Approval waits on a spec decision: this pull request amends Token.spec.md FR10 and AR2 so a clickable Token sends aria-labelledby and aria-describedby to its inner button, and an engineering owner needs to approve that amendment by commenting /approve-spec <full head SHA> on this pull request (the author may do so as an engineering owner) or keep root routing. The Typeahead naming itself works: the Tab stop now reads "Fruit Apple" with the field's description, and "Favorite fruit Selection Apple" inside an InputGroup. Two fixes are needed either way:
- Amend the Clickable representative state in
Token.spec.md("One inner button named by the label") to match the amended AR2. - Add a
## Writing rubric resultssection to the description, which a record change needs before spec approval.
[Automated review]
| - **AR2 — Names.** In the clickable and link-and-remove structures the inner | ||
| button or link takes its name from the Label. In the link structure the link | ||
| button or link takes its name from the Label, or, in the clickable structure, | ||
| from a caller `aria-labelledby` (FR10). In the link structure the link |
There was a problem hiding this comment.
The Clickable representative state at line 148 still says "One inner button named by the label". With this AR2 a caller aria-labelledby names that button instead, so the record now gives two answers; amend line 148 with it, for example "One inner button named by the label, or by a caller aria-labelledby (FR10)".
…r a caller aria-labelledby)
|
/approve-spec 2c48ffb |
Typeahead tests keep both sides: this branch's token-naming tests and main's aria-required / aria-invalid tests.
|
/approve-spec 8ce2342 |
There was a problem hiding this comment.
This looks ready to merge: the value token's Tab stop now reads "Fruit Apple" with the field's description and error, including inside an InputGroup and with a caller aria-labelledby, and the Token.spec.md FR10 and AR2 amendment it relies on has engineering-owner approval for this head. The earlier requests, the Clickable representative state and the writing-rubric results, are both addressed, so nothing more is needed from you.
[Automated review]
User impact
Typeaheadtakes its input out of the Tab order, so the Tab stop is the value's token button. That button was named by the value alone. A screen-reader user tabbing into a form heard "Apple, button", with no field name, description or error, and could not tell which of several Typeaheads it belonged to.aria-labelledby, that label joins the field label as it does on the input), and described by the field's description and status message, like the input.Fixes #8945.
Spec
The specification session decided this: the field label names the field's primary control (
family:input-fieldsFR10 and Field's labelling), so the token button holding the value is named by the field label plus the value and described by the field's description and status (WCAG 2.4.6, 4.1.2).Typeahead.spec.mdis draft.Changes
Typeahead.tsx:aria-labelledbywhen given), plus a hidden span holding the value;aria-describedbythe same ids as the input.Token.tsx: a clickable token passesaria-labelledbyandaria-describedbyto its inner button, the element that owns its action (architecture:public-component-apiINV5). Before, they landed on the generic root span, where they named nothing. Other structures keep them on the root.Token.spec.md(current): FR10 and AR2 record that a clickable token'saria-labelledbyandaria-describedbyreach its inner button; the FR10 verification row checks it. A disabled link token keeps them on its root, with a test.[fix].Evidence
Scope
Writing rubric results
Run over the
component:Tokendelta (FR10, AR2, the Clickable representative state, and the FR2/FR10 verification row):#followed by digits,/pull/and/issues/finds nothing in the record.