D.Dev
D.Dev

Reputation: 15

Screen reader cannot read the visible text inside anchor tag

I have a angular app and it has a drop down menu as below

I use NVDA reader to read the screen.Here when I tab focus it only reads the content inside aria-label.I want it to read the aria label content and other text ('Account',username,email) inside the anchor tag also.

navigation.tpl.html

<ul id="accountMenu" class="dropdown-menu" role="menu">
  <li class="account" ng-click="openDialog($event)">
    <a class="account-container" role="button" aria-label="Open dropdown" href="#">
      <div href="#" class="dropdown-menu">Account</div>
      <div class="account-name">{{ ::username }}</div>
      <div class="account-email" ng-bind="::email"></div>
    </a>
  </li>
</ul>

Upvotes: 0

Views: 3273

Answers (1)

GrahamTheDev
GrahamTheDev

Reputation: 24825

In your example you overwrote the "account, username, email" text with the aria-label.

aria-label works as a "say this instead of the contents of this element to a screen reader" attribute, overriding the information within.

If you ever want to add additional information you should look at aria-labelledby.

However I always encourage people away from using aria-label and use visually hidden text instead.

It all boils down to support aria-label doesn't have perfect support, whereas visually hidden text will work all the way back to IE6!

Also visually hidden text works on browsers that do not support CSS (text only browsers), a nice added bonus.

I have created a snippet below to show you how to do this.

Additional point on semantics

Please note i have also added a second example within the snippet where I changed your anchor (<a>) to a <button>.

Semantics matter, a button indicates an action on the same page, an anchor indicates navigating to another page. Adding role="button" to an anchor with no target destination (#) is way more complicated than using a <button> and is far less robust than just using a button in the first place!

It may take a little CSS fiddling but I would suggest you try and follow that pattern of buttons for same page actions, anchors for navigation as it will make your life easier.

Why not just use .sr-only

If you wonder why I would recommend this custom CSS class for hiding text over the standard .sr-only class in bootstrap etc. here is the original explanation I made on Stack Overflow explaining the issues with .sr-only classes as they stand today.

.visually-hidden { 
    border: 0;
    padding: 0;
    margin: 0;
    position: absolute !important;
    height: 1px; 
    width: 1px;
    overflow: hidden;
    clip: rect(1px 1px 1px 1px); /* IE6, IE7 - a 0 height clip, off to the bottom right of the visible 1px box */
    clip: rect(1px, 1px, 1px, 1px); /*maybe deprecated but we need to support legacy browsers */
    clip-path: inset(50%); /*modern browsers, clip-path works inwards from each corner*/
    white-space: nowrap; /* added line to stop words getting smushed together (as they go onto seperate lines and some screen readers do not understand line feeds as a space */
}
<ul id="accountMenu" class="dropdown-menu" role="menu">
  <li class="account" ng-click="openDialog($event)">
    <a class="account-container" role="button" href="#">
      <span class="visually-hidden">Open dropdown</span>
      <div href="#" class="dropdown-menu">Account</div>
      <div class="account-name">{{ ::username }}</div>
      <div class="account-email" ng-bind="::email"></div>
    </a>
  </li>
</ul>

<h2>A suggestion to improve this further</h2>

<ul id="accountMenu" class="dropdown-menu" role="menu">
  <li class="account" ng-click="openDialog($event)">
    <button class="account-container">
      <span class="visually-hidden">Open dropdown</span>
      <div href="#" class="dropdown-menu">Account</div>
      <div class="account-name">{{ ::username }}</div>
      <div class="account-email" ng-bind="::email"></div>
    </button>
  </li>
</ul>

Upvotes: 1

Related Questions