Visitar URL original
fix(banner): resolve aria-controls in usa-banner web component by ryparker · Pull Request #7011 · uswds/uswds · GitHub
Skip to content

fix(banner): resolve aria-controls in usa-banner web component - #7011

Draft
ryparker wants to merge 1 commit into
developfrom
fix/banner-aria-controls
Draft

ryparker wants to merge 1 commit into
developfrom
fix/banner-aria-controls

Conversation

@ryparker

Copy link
Copy Markdown
Member

Summary

Fixed the <usa-banner> web component so its toggle button points to the content it opens. The button's aria-controls now resolves to the banner content inside the component, and the button's expanded state always matches whether that content is showing.

Breaking change

This is not a breaking change. Default rendering, styles, and click behavior are unchanged. See the note on isOpen under Solution.

Related issue

No open issue tracks this. Related work:

Related pull requests

None. No documentation site change is needed.

Problem statement

The web component banner's "Here's how you know" button has aria-controls="gov-banner-default", but nothing inside the component has that id. The button and the content both live in the component's shadow root, so the reference can only resolve there, and it resolves to nothing. Assistive technology that uses aria-controls to describe or move to the controlled region can't find it, and automated checkers such as axe report the broken reference whenever the banner is expanded.

The same code path had a second mismatch. The component keeps its open state in isOpen and uses it for aria-expanded and the expanded header style, but it showed and hid the content by toggling the hidden attribute separately. When isOpen was set directly, for example with <usa-banner isopen>, the button reported "expanded" while the content stayed hidden. With aria-controls working, that mismatch would point people to hidden content.

This affects screen reader and other assistive technology users on every page of any site that uses the <usa-banner> web component, since the banner sits at the top of each page.

Solution

  • Gave the banner content region id="gov-banner-default". It shares a shadow root with the button, so the existing aria-controls value now finds it. The button's markup does not change, and the id matches the classic banner. Each banner has its own shadow root, so the id doesn't collide when a page has more than one banner or also has a classic banner.
  • Bound the content's hidden attribute to isOpen, and reduced toggle() to flipping isOpen. aria-expanded, the expanded header style, and the content's visibility now come from the same value.
  • Added unit tests showing that aria-controls resolves to the content within the component, that two banners on one page keep their references separate, and that aria-expanded matches the content's visibility when isOpen is set as a property or as an attribute.

A plain id reference works here because the button and the content are in the same shadow root, so this doesn't need cross-root ARIA, which browsers don't fully support yet.

One behavior change: setting isOpen directly now actually opens the content. Before, it only changed the header style and aria-expanded. isOpen isn't documented as an attribute, so this fixes a bug rather than changing the API.

AI disclosure

What AI tools did you use to create this MR?

  • No AI
  • Chat
  • Completions (e.g. Copilot)
  • Coding Agent

Author's checklist

  • Removed redundant AI comments (if applicable)
  • The changes on this PR are strictly limited to the ticket requirements (i.e., no scope creep)
  • I personally witnessed this code working in a local environment
  • Automated tests are passing
  • I have manually tested accessibility using physical devices and relevant assistive technology
    • [List the physical devices and assistive technology here]
  • I understand all the code and could debug it without AI 6 months from now

Testing and review

  1. Run npm run build, then load dist/components/usa-banner.js.mjs on a page that contains <usa-banner></usa-banner>.
  2. In the browser's developer tools, open the banner's shadow root. The button's aria-controls value should match the id on .usa-banner__content.
  3. Activate "Here's how you know" with a mouse, Enter, and Space. aria-expanded should switch between true and false as the content shows and hides.
  4. Add <usa-banner isopen></usa-banner>. It should render open, with aria-expanded="true". On develop, the button reports expanded while the content stays hidden.
  5. With a screen reader, check that the button is announced as collapsed or expanded to match what's on screen.

The web component's toggle button set aria-controls="gov-banner-default",
but no element in its shadow root had that id, so the reference pointed at
nothing. Give the content region that id so the reference resolves inside
the same shadow root, matching the classic banner markup.

Derive the content's hidden state from isOpen instead of toggling the
attribute by hand, so aria-expanded and the content's visibility always
agree, including when isOpen is set directly.
@coderabbitai

coderabbitai Bot commented Oct 15, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

Hi @ryparker — thanks for your contribution!

There is one thing that may be holding this up: for security reasons, USWDS requires that all commits to this repo have a verified commit. The following commit(s) on this PR aren't verified:

  • 20621b1 — fix(banner): resolve aria-controls in usa-banner web component

Here's what's needed:

  1. Set up signature verification in GitHub. Use one of the following GitHub guides to set up your verification signature:

  2. Rebase your commits with your verified signature. Once your signature is set up, complete the following steps in the terminal to update the verification status of your previous commits:

    git checkout fix/banner-aria-controls
    git rebase origin/develop
    git push --force-with-lease

Please let us know if you have any questions. We appreciate your help here. This comment will update automatically once your commits are verified.

@github-actions github-actions Bot added the Needs: Author Response 🔴 Waiting on a specific author action; also used by commit-signature automation. label Oct 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Needs: Author Response 🔴 Waiting on a specific author action; also used by commit-signature automation.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant