Search code examples
nvda

NVDA Chrome reads anchor text inside a hidden div twice when displayed


Anchor link text inside of a hidden div with aria-live="polite" reads twice when displayed in Chrome with the latest NVDA 2022.4.0.27401. It also reads this twice in older versions of NVDA from 2021. You can click the button or run the JavaScript command doIt() from the console to reproduce the issue.

Is there something I should do differently to prevent this?

<html>
<body>

<input type="button" onClick="doIt()" value="Click Me" />

<div aria-live="polite" id="foo" style="display:none">
    <div>some text</div>
    <a href="http://google.com">Some link</a>
</div>

<Script>
    function doIt() {
        var element = document.getElementById('foo');
        element.style.display = "block";
    }
</Script>
</html>

Solution

  • Ignoring the double announcement for the moment, you will get unpredictable results with your code as it's currently written. Live regions are intended to announce changes to their contents. So if you have

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

    and you add/change child elements to that <div>, it will be announced. However, hiding/unhiding the <div> itself may not be announced because the <div> is not contained in a live region. It is a live region but is not contained in a live region, if that makes sense.

    With your sample code, nothing is announced with NVDA or JAWS on Firefox. (It does announce, twice, on Chrome.) If you want to guarantee that your change is announced, you need to put the <div> that you want to unhide inside a live region.

    I tweaked your code slightly by adding a parent container <div> and put aria-live on that container, but kept the ID=FOO on your original (now nested) <div>.

    <div aria-live="polite">
      <div id="foo" style="display:none">
        <div>some text</div>
        <a href="http://google.com">Some link</a>
      </div>
    </div>
    

    Now when I click on the "click me" button, a child <div> is unhidden and since that child is contained in a live region, it is announced correctly in all browsers (albeit the link is still announced twice on Chrome).

    Now, that being said, your original code is not causing the problem with the double link announcement. I get the same double announcement with my tweaked code, but only on Chrome. The tweaked code sounds ok on Firefox and Safari (iOS). Your original code does not announce anything on Firefox.

    So this isn't your problem, or rather, the problem is not caused by your code. (I guess it is your problem if you're trying to prevent the double announcement, but hacking around someone else's bug is not usually a good idea.)

    My best guess is a bug with NVDA on Chrome, possibly related to this bug: https://github.com/nvaccess/nvda/issues/7996

    Interestingly enough, there are several types of elements that are announced twice. If I have several <div> or <span> elements, instead of a link, it's announced just fine. But any interactive element, whether a link, button, checkbox, etc, the text of the interactive element is announced twice. In fact, if I add tabindex="0" to a <div> or <span>, essentially making it an interactive element, then that <div> is now announced twice as well.