ARIA-атрибуты

Роль ARIA в числовом вводе

ARIA (Accessible Rich Internet Applications) используется для того, чтобы динамические интерфейсы оставались понятными для вспомогательных технологий. В случае числовых полей ключевая задача ARIA — обеспечить корректную передачу значения, диапазона и состояния ошибки, особенно когда визуальное представление отличается от фактического значения.

Числовые поля с форматированием (разделители тысяч, локализация, валютные символы) создают разрыв между тем, что видит пользователь, и тем, что должно быть интерпретировано программно. Именно здесь ARIA становится критически важным слоем согласования.


Особенности AutoNumeric и влияние на доступность

AutoNumeric изменяет отображение значения input-поля в реальном времени, преобразуя «сырое» число в форматированную строку.

Это создаёт две ключевые проблемы для доступности:

  • screen reader может озвучивать форматированное значение некорректно или избыточно
  • пользователь вспомогательных технологий может не понимать границы допустимого диапазона
  • состояние ошибки может быть визуально очевидным, но семантически не объявленным

Поэтому интеграция ARIA-атрибутов должна учитывать:

  • разделение raw value и formatted value
  • синхронизацию состояния при каждом изменении ввода
  • явное описание ограничений диапазона

Ключевые ARIA-атрибуты для числовых полей

aria-valuenow

Используется для передачи текущего числового значения в семантическом виде.

При работе с AutoNumeric важно передавать неформатированное значение, а не строку с символами валюты.

element.setAttribute('aria-valuenow', autoNumeric.getNumber());

aria-valuemin и aria-valuemax

Определяют допустимый диапазон значений.

Особенно важно при использовании конфигураций с ограничениями:

element.setAttribute('aria-valuemin', 0);
element.setAttribute('aria-valuemax', 10000);

Если диапазон динамический, атрибуты должны обновляться при изменении конфигурации AutoNumeric.


aria-invalid

Используется для обозначения ошибки валидации.

AutoNumeric не всегда отвечает за бизнес-валидацию, поэтому этот атрибут часто управляется внешней логикой:

if (value < 0 || value > 1000) {
  element.setAttribute('aria-invalid', 'true');
} else {
  element.setAttribute('aria-invalid', 'false');
}

aria-describedby

Связывает поле с текстовым описанием ошибок или подсказок.

<input id="amount" aria-describedby="amount-help amount-error">
<div id="amount-help">Введите сумму в пределах лимита</div>
<div id="amount-error"></div>

Динамическое обновление:

errorElement.textContent = 'Недопустимое значение';
input.setAttribute('aria-invalid', 'true');

aria-live

Используется для объявления изменений значений или ошибок без фокуса.

Полезно при динамическом пересчёте суммы:

<div aria-live="polite" id="summary"></div>
summary.textContent = `Текущее значение: ${autoNumeric.getNumber()}`;

Связка AutoNumeric с ARIA-состояниями

При каждом изменении значения необходимо синхронизировать:

  • визуальное значение (formatted)
  • логическое значение (raw)
  • ARIA представление (semantic)

Типовой обработчик:

const anElement = new AutoNumeric(input, {
  decimalPlaces: 2
});

input.addEventListener('input', () => {
  const value = anElement.getNumber();

  input.setAttribute('aria-valuenow', value);

  if (value === null || isNaN(value)) {
    input.setAttribute('aria-invalid', 'true');
  } else {
    input.setAttribute('aria-invalid', 'false');
  }
});

Роль spinbutton и семантика input

В некоторых сценариях числовое поле может восприниматься как аналог spinbutton. Тогда корректная разметка включает:

<input
  role="spinbutton"
  aria-valuemin="0"
  aria-valuemax="100"
  aria-valuenow="50"
/>

AutoNumeric при этом не должен ломать семантику роли, а лишь обновлять значения атрибутов.


Проблема форматирования и screen readers

Основной риск — чтение форматированной строки:

  • «1 000 000,00 $» может быть озвучено некорректно
  • разделители тысяч могут восприниматься как паузы или символы
  • валютный символ может быть прочитан отдельно

Решение заключается в том, чтобы:

  • не полагаться на textContent как источник семантики
  • всегда обновлять aria-valuenow
  • при необходимости скрывать форматированное значение через aria-hidden на декоративных элементах

Скрытие визуального форматирования от вспомогательных технологий

В некоторых интерфейсах используется отдельный слой отображения:

<span aria-hidden="true" class="formatted-value"></span>
<input aria-valuenow="1000" />

Такой подход предотвращает двойное чтение значения.


Синхронизация ошибок валидации

Типовой паттерн обработки ошибок:

function validate(value) {
  const errorEl = document.getElementById('amount-error');

  if (value < 0) {
    errorEl.textContent = 'Значение не может быть отрицательным';
    input.setAttribute('aria-invalid', 'true');
    input.setAttribute('aria-describedby', 'amount-error');
    return;
  }

  errorEl.textContent = '';
  input.setAttribute('aria-invalid', 'false');
}

Динамическое обновление диапазонов

При изменении конфигурации AutoNumeric (например, переключение валюты):

autoNumeric.update({
  minimumValue: '0',
  maximumValue: '999999'
});

input.setAttribute('aria-valuemin', '0');
input.setAttribute('aria-valuemax', '999999');

Интеграция с кастомными событиями AutoNumeric

AutoNumeric предоставляет события изменения значений, которые используются для синхронизации ARIA:

input.addEventListener('autoNumeric:formatted', () => {
  input.setAttribute('aria-valuenow', autoNumeric.getNumber());
});

При сложных формах рекомендуется централизованный обработчик состояния, чтобы исключить расхождения между UI и ARIA.


Типовые ошибки реализации ARIA с AutoNumeric

  • использование formatted value в aria-valuenow
  • отсутствие обновления aria-invalid при динамической валидации
  • отсутствие aria-describedby при ошибках
  • конфликт role=“spinbutton” с кастомной логикой ввода
  • отсутствие синхронизации при programmatic updates

Практический шаблон интеграции

const an = new AutoNumeric(input, {
  decimalPlaces: 2,
  minimumValue: '0',
  maximumValue: '10000'
});

function syncA11y() {
  const value = an.getNumber();

  input.setAttribute('aria-valuenow', value ?? '');
  input.setAttribute('aria-valuemin', '0');
  input.setAttribute('aria-valuemax', '10000');

  const isValid = value !== null && value >= 0 && value <= 10000;
  input.setAttribute('aria-invalid', String(!isValid));
}

input.addEventListener('input', syncA11y);
input.addEventListener('blur', syncA11y);

Согласование поведения в сложных формах

В формах с несколькими зависимыми полями (например, расчёт итоговой суммы) ARIA обновляется не только на уровне input, но и на уровне агрегированных значений:

<div aria-live="polite" id="total-summary"></div>
summary.textContent = `Итого: ${total}`;
summary.setAttribute('aria-atomic', 'true');

Значение корректной ARIA-реализации

Корректная интеграция ARIA с числовыми форматтерами обеспечивает:

  • предсказуемое поведение screen readers
  • согласованность между визуальным и семантическим представлением
  • корректную обработку ошибок и диапазонов
  • стабильную работу сложных финансовых интерфейсов