1

The issue is I want to make NVDA read some message after pressing a button. For example, there is a button "add new row" which adds new row to a grid. User who uses NVDA screen reader presses Enter on the button and then I want to notify him about the successful result (row has been added). Another example I have a form where user makes some changes. "Save" button is available on the form - after preesing I want to notify the user "changes has been saved". Is there any way to do this without throwing a toaster message? I want to add that in my case after pressing the buttons, focus stays on them.

Denys Alexieiev
  • 224
  • 1
  • 15

2 Answers2

1

You are looking for the aria-live attribute

This allows you to provide updates to a screen reader user by changing the text inside the container that has aria-live on it.

For your use case you want to use aria-live="polite", aria-live="assertive" should only be used for time sensitive information such as alerts for being logged out etc.

An aria-live region that is not visible

You do not have to have a visible aria-live region, but it must be accessible by a screen reader.

For that we can make it visually hidden using my visually hidden class (which is better than sr-only and is future proofed as clip has been deprecated)

.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 */
}
<div class="visually-hidden" aria-live="polite">

Whatever you put in here via JavaScript will get read out to screen readers as an appropraite quiet time. This is not visible.

</div>

<p>This is visible</p>

Example from MDN

As link only answers are never good I have included the example from the linked article on MDN.

const PLANETS_INFO = {
  mercury: {
    title: 'Mercury',
    description: 'Mercury is the smallest and innermost planet in the Solar System. It is named after the Roman deity Mercury, the messenger to the gods.'
  },

  venus: {
    title: "Venus",
    description: 'Venus is the second planet from the Sun. It is named after the Roman goddess of love and beauty.'
  },
  
  earth: {
    title: "Earth",
    description: 'Earth is the third planet from the Sun and the only object in the Universe known to harbor life.'
  },
  
  mars: {
    title: "Mars",
    description: 'Mars is the fourth planet from the Sun and the second-smallest planet in the Solar System after Mercury. In English, Mars carries a name of the Roman god of war, and is often referred to as the "Red Planet".'
  }
};

function renderPlanetInfo(planet) {
  const planetTitle = document.querySelector('#planetTitle');
  const planetDescription = document.querySelector('#planetDescription');
  
  if (planet in PLANETS_INFO) {
    planetTitle.textContent = PLANETS_INFO[planet].title;
    planetDescription.textContent = PLANETS_INFO[planet].description;
  } else {
    planetTitle.textContent = 'No planet selected';
    planetDescription.textContent = 'Select a planet to view its description';
  }
}

const renderPlanetInfoButton = document.querySelector('#renderPlanetInfoButton');

renderPlanetInfoButton.addEventListener('click', event => {
  const planetsSelect = document.querySelector('#planetsSelect');
  const selectedPlanet = planetsSelect.options[planetsSelect.selectedIndex].value;

  renderPlanetInfo(selectedPlanet);
});
<fieldset>
  <legend>Planet information</legend>
  <label for="planetsSelect">Planet:</label>
  <select id="planetsSelect" aria-controls="planetInfo">
    <option value="">Select a planet&hellip;</option>
    <option value="mercury">Mercury</option>
    <option value="venus">Venus</option>
    <option value="earth">Earth</option>
    <option value="mars">Mars</option>
  </select>
  <button id="renderPlanetInfoButton">Go</button>
</fieldset>

<div role="region" id="planetInfo" aria-live="polite">
  <h2 id="planetTitle">No planet selected</h2>
  <p id="planetDescription">Select a planet to view its description</p>
</div>

<p><small>Information courtesy <a href="https://en.wikipedia.org/wiki/Solar_System#Inner_Solar_System">Wikipedia</a></small></p>
GrahamTheDev
  • 22,724
  • 2
  • 32
  • 64
  • Thank you for your answer. Does it mean that the container with the aria-live attribute should be visible on the screen? Or I can make him invisible? – Denys Alexieiev Nov 03 '20 at 18:16
  • You can make it invisible but for that use visually hidden text, give me a second I will link to that. – GrahamTheDev Nov 03 '20 at 18:17
  • my point just is that this information (new record has been added to table) is not needed to sighted user because he can see it visually. So I think this text should be only available for not sighted users. Although I do not really know what is the pattern for such situations. Probably I am wrong and the message should also be available for sighted users. – Denys Alexieiev Nov 03 '20 at 18:20
  • 1
    Normally I would say make sure it is visible for everyone, so for example "changes have been saved" is useful for everyone. However a new row being added is easy to see visually so for that you can use a hidden `aria-live` region. I have added an example for you to my answer. – GrahamTheDev Nov 03 '20 at 18:21
  • Thank you. How do you think is it an option to skip such notifications if only non-sighted users should be notified? – Denys Alexieiev Nov 03 '20 at 18:38
  • 1
    that is exactly what I meant, adding a new row to a table is easily seen visually (assuming the button is well placed and located next to where the new row appears) so no need for a visual notification, however a screen reader user needs to know it was successful if you need to contact the server before adding the new row, they also need notifications if it fails (that should be `aria-live="assertive"`), but then sighted users also need that information. Basically if there is a very evident visual change then no need for a toast etc. – GrahamTheDev Nov 04 '20 at 08:51
0

Screen reader only text is recommended for information that's apparent visually but not available for non sighted users. I suggest that you try using clip + clip-path method as progressive enhancements to support both older and newer browser versions.

.screenreader-text {
  border: 0;
  /*Clipping defines what part of an element should be displayed*/
  /* Deprecated clip property for older browsers */
  clip: rect(1px, 1px, 1px, 1px);
  /* clip-path for newer browsers. inset(50%) defines an inset rectangle that makes the content disappear */
  clip-path: inset(50%);
  height: 1px;
  margin: -1px;
  overflow: hidden;
  padding: 0;
  position: absolute !important;
  width: 1px;
  word-wrap: normal !important;
}

  
user 9631883
  • 466
  • 5
  • 14
  • I am intrigued, why have you got focus and active pseudo selectors? No active / focusable elements should be visually hidden so is this for some strange edge case as I will update my CSS if so! A couple of things need tweaking in your main class that I covered in [this answer](https://stackoverflow.com/a/62109988/2702894) if it interests you such as negative margin and `word-wrap`. – GrahamTheDev Nov 04 '20 at 09:41
  • 1
    In my current job, though not recommended, developers sometimes place navigable elements within offscreen text(esp. when Search filter is present after the Search text box and Search button. After selecting filters, tabbing would dynamically display a link that takes focus back to the Search area which is earlier in the reading order). So included :focus and :active styles to cover such scenario. Thanks for the suggestion, I could remove the active and focus states in my original answer so that doesn't confuse anyone. – user 9631883 Nov 04 '20 at 10:01
  • 1
    ahhh I see, in that scenario when they tab to it they should make the link visible, similar to a skip link. (hide it unless it has focus) This is because you have sighted keyboard users (who may have mobility issues for example) who would be very confused by a tab stop that goes nowhere as far as they are concerned (as they can't see it), so you would fail [WCAG 2.4.3 focus order](https://www.w3.org/TR/UNDERSTANDING-WCAG20/navigation-mechanisms-focus-order.html) – GrahamTheDev Nov 04 '20 at 10:10