Skip to content

JAWS key + Alt + M announces "moved to controlled element" but does not move when the aria-controls target is a named region #966

Open

Description

@web-padawan

Summary

When a button with aria-controls points to an element with role="region" and an accessible name, JAWS announces "moved to controlled element" after JAWS key + Alt + M, but the virtual cursor stays on the button.

The same page works when the target is a plain <div>, or a role="region" without a name (which Chromium exposes as generic). So the trigger is the target being a landmark, not the role attribute or the way the name is given: aria-label and aria-labelledby both reproduce it.

The browser exposes the controls relation and the region in all three cases (checked with the Chrome DevTools accessibility panel). The behavior is the same in Chrome and Firefox.

Steps:

  1. Save the example below as an HTML file and open it in Chrome or Firefox.
  2. Tab to the "Show region" button and press Enter to expand the content.
  3. Press JAWS key + Alt + M.
  4. Repeat for the "Show plain" and "Show unnamed region" buttons.

Expected result

The virtual cursor moves to the controlled element in all three cases, like it does for "Show plain".

Actual result

  • "Show region": JAWS says "moved to controlled element", the virtual cursor stays on the button and the next arrow key reads the button again.
  • "Show plain": the virtual cursor moves to the content.
  • "Show unnamed region": the virtual cursor moves to the content.

Example

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>aria-controls target with role=region</title>
  </head>
  <body>
    <h2>Fails: target is a named region</h2>

    <button type="button" aria-expanded="false" aria-controls="regionContent">Show region</button>

    <div hidden>
      <div id="regionContent" role="region" aria-label="Region details">
        <p>Region content.</p>
      </div>
    </div>

    <h2>Works: target is a plain div</h2>

    <button type="button" aria-expanded="false" aria-controls="plainContent">Show plain</button>

    <div hidden>
      <div id="plainContent">
        <p>Plain content.</p>
      </div>
    </div>

    <h2>Works: target is a region without a name</h2>

    <button type="button" aria-expanded="false" aria-controls="unnamedContent">Show unnamed region</button>

    <div hidden>
      <div id="unnamedContent" role="region">
        <p>Unnamed region content.</p>
      </div>
    </div>

    <script>
      document.querySelectorAll('button[aria-controls]').forEach((button) => {
        const wrapper = document.getElementById(button.getAttribute('aria-controls')).parentElement;
        button.addEventListener('click', () => {
          const expanded = button.getAttribute('aria-expanded') === 'true';
          button.setAttribute('aria-expanded', String(!expanded));
          wrapper.hidden = expanded;
        });
      });
    </script>
  </body>
</html>

This is the content container of an accordion built after the APG accordion pattern, which recommends role="region" with aria-labelledby pointing to the heading. With that markup, the aria-controls link from the heading button cannot be followed in JAWS.

Additional Information

JAWS version and build number

JAWS 2026.2608.25

Operating System and version

Windows

Browser and version:

Chrome and Firefox, current stable versions, both reproduce the issue.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions