UNPKG

4.25 kBJavaScriptView Raw
1/**
2 * @license
3 * Copyright 2018 Google Inc.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 * THE SOFTWARE.
22 */
23import { numbers, strings } from './constants';
24var ARIA_LIVE_DELAY_MS = numbers.ARIA_LIVE_DELAY_MS;
25var ARIA_LIVE_LABEL_TEXT_ATTR = strings.ARIA_LIVE_LABEL_TEXT_ATTR;
26function announce(ariaEl, labelEl) {
27 if (labelEl === void 0) { labelEl = ariaEl; }
28 var priority = ariaEl.getAttribute('aria-live');
29 // Trim text to ignore ` ` (see below).
30 // textContent is only null if the node is a document, DOCTYPE, or notation.
31 var labelText = labelEl.textContent.trim();
32 if (!labelText || !priority) {
33 return;
34 }
35 // Temporarily disable `aria-live` to prevent JAWS+Firefox from announcing the message twice.
36 ariaEl.setAttribute('aria-live', 'off');
37 // Temporarily clear `textContent` to force a DOM mutation event that will be detected by screen readers.
38 // `aria-live` elements are only announced when the element's `textContent` *changes*, so snackbars
39 // sent to the browser in the initial HTML response won't be read unless we clear the element's `textContent` first.
40 // Similarly, displaying the same snackbar message twice in a row doesn't trigger a DOM mutation event,
41 // so screen readers won't announce the second message unless we first clear `textContent`.
42 //
43 // We have to clear the label text two different ways to make it work in all browsers and screen readers:
44 //
45 // 1. `textContent = ''` is required for IE11 + JAWS
46 // 2. `innerHTML = ' '` is required for Chrome + JAWS and NVDA
47 //
48 // All other browser/screen reader combinations support both methods.
49 //
50 // The wrapper `<span>` visually hides the space character so that it doesn't cause jank when added/removed.
51 // N.B.: Setting `position: absolute`, `opacity: 0`, or `height: 0` prevents Chrome from detecting the DOM change.
52 //
53 // This technique has been tested in:
54 //
55 // * JAWS 2019:
56 // - Chrome 70
57 // - Firefox 60 (ESR)
58 // - IE 11
59 // * NVDA 2018:
60 // - Chrome 70
61 // - Firefox 60 (ESR)
62 // - IE 11
63 // * ChromeVox 53
64 labelEl.textContent = '';
65 labelEl.innerHTML = '<span style="display: inline-block; width: 0; height: 1px;">&nbsp;</span>';
66 // Prevent visual jank by temporarily displaying the label text in the ::before pseudo-element.
67 // CSS generated content is normally announced by screen readers
68 // (except in IE 11; see https://tink.uk/accessibility-support-for-css-generated-content/);
69 // however, `aria-live` is turned off, so this DOM update will be ignored by screen readers.
70 labelEl.setAttribute(ARIA_LIVE_LABEL_TEXT_ATTR, labelText);
71 setTimeout(function () {
72 // Allow screen readers to announce changes to the DOM again.
73 ariaEl.setAttribute('aria-live', priority);
74 // Remove the message from the ::before pseudo-element.
75 labelEl.removeAttribute(ARIA_LIVE_LABEL_TEXT_ATTR);
76 // Restore the original label text, which will be announced by screen readers.
77 labelEl.textContent = labelText;
78 }, ARIA_LIVE_DELAY_MS);
79}
80export { announce };
81//# sourceMappingURL=util.js.map
\No newline at end of file