htmlaccessibilityvoiceoverscreen-readers

Linebreak in a H1 turns the element into a VoiceOver group


I am using a <br> inside a <h1> for design reasons eg:

<h1>This is a <br>headline</h1>

But have noticed that it will turn the element into a "group" that VoiceOver reads as separate items, something like:

Heading level 1 "This is a ... headline"
Group 3 items
"This is a"
"headline"
"Empty group"

Adding aria-hidden="true" or role="presentation" attributes to the <br> only removes the "empty group" announcement, but VoiceOver still considers the H1 to be a "group".

Is it possible to have br element present inside h1 without having it announced as "group" by VoiceOver?


Solution

  • I wanted to consolidate some of the comments to make it easier to read.

    But first a clarification. The "group" announcement is with VoiceOver on a Mac. You do not hear "group" with VoiceOver on iOS. I don't have a Mac to test these but I did try it on my iPhone.

    Regardless of the "group" announcement, my testing is mainly for hearing the heading as one element instead of split in two, although semantically your heading is two elements since you have a <br>. This is beside the point of the original question since you were mainly asking how to remove the "group" announcement and not how to read the heading as one element. But nonetheless, here are some testing results for forcing the heading to be read as one. The last example might have a side bonus of eliminating the "group" announcement.

    The following ideas have been proposed:

    Original code:

    <h1>This is a <br>headline</h1>
    

    When swiping right with VO on iOS:

    NVDA on a PC, using the down arrow to navigate:

    JAWS on a PC, using the down arrow to navigate:

    Other than the "group" announcement on a Mac, this is what I would expect.

    First suggestion:

    <h1 aria-label="This is a headline">This is a <br>headline</h1>
    

    When swiping right with VO on iOS:

    Since the heading is still two elements (because of the <br>) but an aria-label is applied (*), you hear the aria-label for both parts of the heading.

    (*) Note that the aria-label overrides child elements when used properly, which will be addressed below after all these examples.

    NVDA on a PC, using the down arrow to navigate:

    There is no second element for NVDA when an aria-label is applied because the aria-label replaces the contents of all child elements. See https://www.w3.org/TR/wai-aria-practices-1.2/#naming_with_aria-label, in particular:

    When applied to an element with one of the roles that supports naming from child content, aria-label hides descendant content from assistive technology users and replaces it with the value of aria-label.

    If you follow the naming from child content link, a heading is one of the elements.

    JAWS on a PC, using the down arrow to navigate:

    The aria-label is completely ignored by JAWS and you get the same result as the original code.

    Second suggestion:

    <h1 aria-label="This is a headline"><span aria-hidden="true">This is a <br>headline</span></h1>
    

    When swiping right with VO on iOS:

    There is no second element. The aria-label is honored and the aria-hidden essentially hides the inner text of the heading itself. aria-hidden really should have no effect because the aria-label is going to override all child elements (*) as noted above.

    (*) Note that the aria-label overrides child elements when used properly, which will be addressed below after all these examples.

    NVDA on a PC, using the down arrow to navigate:

    There is no difference for NVDA. The aria-hidden has no affect, which is what I expected and which is why I was confused that it affected VoiceOver.

    JAWS on a PC, using the down arrow to navigate:

    Nothing is read, presumably because of the aria-hidden and because JAWS does not honor aria-label on a heading, which is part of the (*) comment below. Since JAWS doesn't see the aria-label and the contents of the heading are hidden, there is nothing to read.

    Third suggestion:

    <h1><span role="text">This is a <br>headline</span></h1>
    

    When swiping right with VO on iOS:

    There is no second element because the role="text" takes away all child elements and just concatentes the text. However, VO announces it slightly different than the previous example and has a brief pause between the "a" and "headline", as if there was a comma between them.

    NVDA on a PC, using the down arrow to navigate:

    JAWS on a PC, using the down arrow to navigate:

    Since role="text" is not an approved role, there is no difference in this example compared to the original with NVDA or JAWS. However, Apple implemented the role and it's honored with VoiceOver and it does sometimes come in handy as long as you realize it will not have an affect with other screen readers. I've used role="text" in production level code with the caveat that support could be taken away at anytime by Apple. But that production code was written 10 years ago and it's still working great.

    (*) comment about using aria-label properly

    Take a look at "2.10 Practical Support: aria-label, aria-labelledby and aria-describedby", in particular the 7th bullet point:

    Don't use aria-label or aria-labelledby on any heading elements because it overrides them on NVDA, VoiceOver and Talkback. **JAWS ignores them. **

    So the idea of using an aria-label on a heading is strongly discouraged.

    One way to have the heading read as one line that is supported by all screen readers AND might eliminate the "group" announcement

    <h1>
      <span aria-hidden="true">
        This is a <br>headline
      </span>
      <span class="sr-only">
        This is a headline
      </span>
    </h1>
    

    You essentially have two headings. The first one is for the sighted user, which is ignored by the screen reader, and the second one is for the screen reader user, which will not be displayed for the sighted user.

    The "sr-only" class is nothing special. It's just a common name to use for "screen reader only" CSS. You can see more about it at What is sr-only in Bootstrap 3?

    I believe this example will also eliminate the "group" announcement but I don't have a Mac to test that.