Skip to content

fix(core): complete disclosure ARIA wiring in ChatToolCalls#3720

Merged
cixzhang merged 1 commit into
facebook:mainfrom
bhamodi:a11y/chat-toolcalls-disclosure
Jul 10, 2026
Merged

fix(core): complete disclosure ARIA wiring in ChatToolCalls#3720
cixzhang merged 1 commit into
facebook:mainfrom
bhamodi:a11y/chat-toolcalls-disclosure

Conversation

@bhamodi

@bhamodi bhamodi commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Summary

ChatToolCalls had two incomplete disclosure relationships:

  • Expandable call rows (CallRow, with resultDetail) render role="button" + tabIndex={0} and toggle an inline detail panel, but exposed no aria-expanded and no aria-controls, and the detail panel had no id. A screen-reader user heard a plain button with no indication it opens anything or what it controls.
  • The tool-calls group header exposed aria-expanded but had no aria-controls, and its content region (the collapsible list of call rows) had no id -- so the toggle ↔ region relationship was implicit only.

This wires both up with useId()-generated ids:

  • CallRow (ChatToolCalls.tsx:366): aria-expanded (only when the row is expandable) + aria-controls on the row, and id on the detail panel. The detail panel is conditionally mounted (rendered only while open), so aria-controls is set only while the panel is mounted -- it never points at a non-existent id. Matches the aria-controls={... ? ... : undefined} pattern used by the Date inputs (DateInput, etc.) for their conditionally-mounted popovers and the Banner fix (fix(core): link Banner expand toggle to its content via aria-controls #3719).
  • Group header (ChatToolCalls.tsx:555): id on the always-mounted content region + aria-controls on the header. Because the region stays mounted (it collapses via CSS grid-template-rows, not unmount), aria-controls is unconditional -- matching SideNavItem.

Purely additive; no behavior/visual/role change.

Changes

  • Chat/ChatToolCalls.tsx: useId()aria-expanded/aria-controls on expandable call rows + id on the detail panel (set only while mounted); useId()aria-controls on the group header + id on the content region.

Test plan

  • node_modules/.bin/vitest run --root . packages/core/src/Chat -- 126 pass (10 files), including three new ChatToolCalls tests (the two disclosure tests confirmed failing before the fix):
    • exposes no aria-expanded on a call row without resultDetail -- a non-expandable row stays a plain row.
    • wires disclosure semantics on an expandable call row -- asserts aria-expanded="false" and no aria-controls while collapsed, then after click aria-expanded="true" and aria-controls resolving via document.getElementById to the panel containing the detail content.
    • points the group header aria-controls at the content region -- asserts the header's aria-controls resolves to the region containing the call rows.
  • node_modules/.bin/tsc --project packages/core/tsconfig.json --noEmit -- clean.
  • node_modules/.bin/eslint on changed files -- clean.

Notes

Found during a broader a11y audit of core components. Scoped to one fix per PR. Mirrors the sibling disclosure fixes on Banner (#3719) and Collapsible (#3707).

@vercel

vercel Bot commented Jul 9, 2026

Copy link
Copy Markdown

@bhamodi is attempting to deploy a commit to the Meta Open Source Team on Vercel.

A member of the Team first needs to authorize it.

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Jul 9, 2026
@bhamodi bhamodi force-pushed the a11y/chat-toolcalls-disclosure branch from 620b1f9 to ba09206 Compare July 9, 2026 05:54

@cixzhang cixzhang left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @bhamodi — disclosure ARIA wiring matches DateInput + SideNavItem; conditional vs unconditional aria-controls both correct. 🙏

@cixzhang cixzhang merged commit e45d9ae into facebook:main Jul 10, 2026
14 of 15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Meta Open Source bot.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants