Модуль 7 · урок 8 з 10
Живі області
Останній шматок доступності: як повідомити про те, що змінилось, людині, яка не бачить екрана. Спінер вона не побачить, зникнення таблиці не помітить, а «Збережено» у кутку екрана для неї не існує. Живі області вирішують саме це.
aria-live
<div aria-live="polite" class="visually-hidden">
{{ statusMessage() }}
</div>
Скрінрідер стежить за вмістом такого елемента й озвучує зміни. Сам елемент має бути в DOM заздалегідь — якщо створити його разом із повідомленням, зміну може бути не помічено.
| Значення | Поведінка | Коли |
|---|---|---|
polite | Дочекається паузи в мовленні | Майже завжди: завантаження, результати, збереження |
assertive | Перерве поточне мовлення | Лише критичне: втрата даних, помилка збереження |
off | Не озвучувати | Значення за замовчуванням |
Він перебиває людину посеред речення. Якщо позначити так усе підряд, користуватись
інтерфейсом стане неможливо — це те саме, що модальне вікно на кожну дію.
Практичне правило: assertive лише там, де без негайної реакції втратяться дані.
Що озвучувати
export class TasksPage {
protected readonly announcement = signal('');
constructor() {
effect(() => {
const s = this.state();
if (s.kind === 'loading') this.say('Завантаження списку задач');
if (s.kind === 'data') this.say(`Знайдено задач: ${s.rows.length}`);
if (s.kind === 'empty') this.say('Задач не знайдено');
if (s.kind === 'error') this.say('Не вдалось завантажити список');
});
}
private say(text: string): void {
this.announcement.set(''); // скинути — інакше однакове повідомлення не прочитається
setTimeout(() => this.announcement.set(text));
}
}
Хитрість зі скиданням потрібна тому, що скрінрідер реагує на зміну тексту. Якщо двічі поспіль встановити те саме значення, другий раз буде проігноровано — а користувач не дізнається, що фільтр застосувався й результат той самий.
Готовий інструмент із CDK
import { LiveAnnouncer } from '@angular/cdk/a11y';
export class TasksPage {
private readonly announcer = inject(LiveAnnouncer);
onSorted(column: string, dir: 'asc' | 'desc'): void {
this.announcer.announce(
`Відсортовано за колонкою ${column}, ${dir === 'asc' ? 'зростання' : 'спадання'}`,
);
}
}
LiveAnnouncer сам створює прихований елемент, керує ним і робить скидання.
Якщо в проєкті вже є Angular CDK — простіше взяти його, ніж робити свій.
Що варто озвучувати в нашому застосунку
| Подія | Повідомлення | Режим |
|---|---|---|
| Почалось завантаження | «Завантаження списку» | polite |
| Дані прийшли | «Знайдено задач: 42» | polite |
| Фільтр не дав результатів | «Нічого не знайдено» | polite |
| Сортування змінилось | «Відсортовано за терміном, спадання» | polite |
| Запис збережено | «Задачу збережено» | polite |
| Помилка збереження | «Не вдалось зберегти» | assertive |
| Сесія завершується | «Сесія завершиться за хвилину» | assertive |
role="alert" і role="status"
<p role="alert">Не вдалось зберегти</p> <!-- = aria-live="assertive" -->
<p role="status">Задачу збережено</p> <!-- = aria-live="polite" -->
Це коротший запис того самого. Для повідомлень про помилки у формах із модуля 6
role="alert" — саме те: воно зʼявляється у відповідь на дію користувача,
тож перебивання доречне.