reactjswindowsaccessibilityscreen-readersnvda

Screen Reader reading properly on Mac chrome but not on Windows Chrome React


I have a scenario where I have added an aria-label to a parent <div> which contains some text. Ideally the aria-label provided to the parent <div> should be narrated first and then the child Text component. This works completely fine on MacOS Chrome with the VoiceOver screen reader, but on Windows Chrome with NVDA the parent <div> aria-label is not at all read.

Attaching a code snippet for reference:

<div aria-label="Parent div accessibility">
     <Text> Some Text </Text> 
</div>

Speech output on MacOS Chrome with VoiceOver:

Narrator - Parent div accessibility
Narrator - Some Text

Speech output on Windows Chrome with NVDA:

Narrator - Some Text

Solution

  • Screen readers are all over the map with respect to interpretting aria-label on non-interactive elements.

    According to David MacDonald's tests, VoiceOver and TalkBack will read the aria-label text on static elements, but JAWS and NVDA will not unless the static content (like a <div>) has the role="navigation", role="search", role="main", or role="img".

    By design, aria-label is meant to override the existing text of an element because it is what most screen readers will interpret as the element's label. So, the behaviour you're getting from VoiceOver is not necessarily standard behaviour. Some screen readers (like TalkBack) will ignore the inner text of your <div> if you use aria-label, because it interprets the aria-label as the label for that element and ignores any other text within the element. Other screen readers like JAWS will read both the aria-label text and the inner text of the <div> if you add a role like role="navigation" to your static element. It seems that NVDA 2018 did support using aria-label on static elements, but it was later removed because there's yet to be consensus on the aria-label debate.

    Option 1

    The fail-safe option would be to use text that is visibly hidden by CSS. This is fully supported by all browser/screen reader combinations.

    Here is the example suggested by WebAIM:

    <style>
        .sr-only {
        position:absolute;
        left:-10000px;
        top:auto;
        width:1px;
        height:1px;
        overflow:hidden;
        }
    </style>
    
    <div class="sr-only">This text is hidden.</div> 
    

    Option 2

    Another option is to use the CSS content property to hide the text that you want spoken by the screen reader, as suggested by slugolicious in a similar question on SO:

    <style>
        div::before {content: "This text is hidden"; font-size: 0px;}  
    </style>
    

    I tested his suggestion with JAWS and NVDA and it announced the "This text is hidden" text as well as the inner text of the <div>.

    However, as QuentinC pointed out in the comments, the CSS content property isn't currently supported by all browser/screen reader combinations.

    For reference:
    Clarify use of aria-label on elements with no role #756
    Woe-ARIA: The Surprisingly but Ridiculously Complicated World of aria-label/ledby
    What happens with aria-labelledby, aria-label and aria-describedby on static HTML elements?
    WebAIM: Invisible Content Just for Screen Reader Users

    Update

    I edited my original answer to include QuentinC's suggestion of using CSS to hide the text.