Search code examples
javascripthtmlaccessibility

Why the role="status" attribute doesn't work correctly?


As the title says, my question is why the role="status" attribute doesn't work correctly. I'm using a screen reader and it doesn't read the paragraph text once it gets appended to the body.

index.html:

<!DOCTYPE html>
<html>
  <head>
    <title>Parcel Sandbox</title>
    <meta charset="UTF-8" />
  </head>

  <body>
    <div id="app">
      <button class="btn">Click</button>
    </div>

    <script src="src/index.js"></script>
  </body>
</html>

index.js:

const btn = document.querySelector(".btn");

btn.onclick = () => {
  if (!document.querySelector(".p")) {
    const p = document.createElement("div");
    p.className = "p";
    p.textContent = "It's a text, right?";
    p.role = "status";
    p.ariaLive = "polite";
    document.body.appendChild(p);
  }
};

I share a codesandbox link as well: https://codesandbox.io/s/goofy-http-cm25wf?file=/src/index.js

I was watching a conference talk about a11y and the code of the speaker worked perfectly. She was using Svelte for the demo and I use vanilla JS but in my opinion that's not the problem since a11y features are not framework-specific.

Here is her codesandbox (which, again, works fine): https://codesandbox.io/s/live-region-a11y-durnhc?file=/Form.svelte


Solution

  • role="status" is a shortcut for specifying a live region with aria-live="polite" and aria-atomic="true". In your example above, setting aria-live="polite" is superfluous since you already have role="status", but that's not what's causing the problem.

    Live regions will cause assistive technology, such as a screen reader, to announce changes to a DOM element. However, adding a live region dynamically is not necessarily supported. Some screen readers might announce the newly added live region and others might not.

    The newly added DOM elements must be added to an existing live region.

    So, for example, if I had:

    <div>
    </div>
    

    and after some user interaction, I added the following via javascript:

    <div>
      <div aria-live="polite">
        I'm new!
      </div>
    </div>
    

    The new text might not be announced because the live region was added rather than the new text being added to an existing live region.

    However, if the original code looked like this:

    <div aria-live="polite">
    </div>
    

    And then new text was added like this:

    <div aria-live="polite">
      <div>
        I'm new!
      </div>
    </div>
    

    Then you would hear it properly announced.

    You'll notice in the codesandbox example you posted, the one that works, the "message" element already exists on the page and text is being added to it. The example does not add the live region.

    <div role="status" aria-live="polite">{message}</div>
    

    Again, the aria-live="polite" is not necessary since role="status" is specified.

    In my examples above, you can remove aria-live="polite" and use role="status" to match your code.