Почему разработчики деактивируют кнопки
По моим наблюдениям, паттерн используется для того, чтобы исключить возможность повторной отправки формы в процессе ожидания, пока обрабатывается первая. Часто случается, что нужно дождаться ответа API и на это требуется несколько секунд; нежелательно, чтобы пользователь успел отослать еще одну форму, пока система не закончит реагировать на предыдущую.
form.addEventListener('submit', function (event) {
// Don't let the form reload the page
event.preventDefault();
// Get the submit button and disable it
let btn = form.querySelector('button');
btn.addAttribute('disabled', '');
// Do more form stuff...
// re-enable the button after the API responds
btn.removeAttribute('disabled');
});
При блокировании button еще раз нажать на кнопку не получится.
Почему этот паттерн не работает
Начнем с того, что он не делает того, на что рассчитан. Одно то, что кнопка блокирована, не означает, что отправить форму становится невозможно. Можно перейти на какое-нибудь из полей формы, нажать на клавишу enter или return – и форма будет отправлена.
Но, помимо этого, метод никуда не годится с точки зрения доступности. Элементы с атрибутом disabled не могут принимать на себя фокус, а это создает путаницу для тех, кто использует скринридеры или перемещается по вебсайтам при помощи клавиатуры.
Если кнопка находится в фокусе в тот момент, когда вы задаете ей атрибут disabled (скажем, пользователь только что нажал на нее, чтобы отправить форму), то фокус переходит с нее на элемент document. Человека со скринридером это собьет с толку – он окажется совершенно в другой части страницы.
То есть, если обобщить сказанное, этот способ не помогает вам достичь поставленной цели и вдобавок портит опыт определенному сегменту ваших пользователей.
Более удачный способ
Что же тогда делать? Лично я предпочитаю добавлять атрибут для элемента form, а затем убирать его, когда все необходимые действия с формой будут произведены. Всякий раз, когда происходит событие submit, в первую очередь проводится проверка на наличие атрибута. Если он в наличии, я прерываю обработчик событий, чтобы предотвратить многократную отправку формы.
form.addEventListener('submit', function (event) {
// Don't let the form reload the page
event.preventDefault();
// If the form is already submitting, do nothing
if (form.hasAttribute('data-submitting')) return;
// Add the [data-submitting] attribute to stop multiple submissions
form.setAttribute('data-submitting', '');
// Do more form stuff...
// Remove the [data-submitting] attribute
form.removeAttribute('data-submitting');
});
Таким образом, фокус на элементах формы сохраняется, никаких проблем с доступностью не возникает, дублирование форм предотвращается, а также блокируется возможность отправить форму путем ввода команд клавишами в других полях.
Вдобавок вы можете придать элементам особый «деактивированный» вид при помощи CSS-селектора [data-submitting]…
[data-submitting] button {
opacity: 0.8;
}
Не забывайте также включать ARIA live region и отображать оповещения о статусе обработки формы на протяжении всего процесса.
Комментарии (4)
y_akopov
22.11.2023 11:21+3На мой взгляд, ваше предложенное решение, когда мы в фоне отправляем запрос (который может, в зависимости от скорости сети, сервера и т.п., длиться Х секунд) и оставляем кнопку активной ведет к дезориентации.
Как пользователь поймет, что кнопка отработала? Может, мышка заглючила и кнопка не нажалась.
Мне кажется, лучшим решением является:
1. блокировать кнопка
2. в кнопке менять текст (если было "Сохранить", то на "Сохраняем..", если было "Изменить", то на "Изменяем.." и т.п., или на обощенное "Пожалуйста, подождите..."
3. добавить слева от текста в кнопке динамичную иконку, по типау ajax-loader
Такой подход однозначно отображает текущее состояние формы.
В случае ошибки, вернуть кнопку в первоначальный вид и отобразить значимое сообщение рядом с кнопкой.
DMGarikk
а еще отправляют формы с помощью стандартного type="submit" ?
я конечно не фронт, но я чёт давно не встречал в своих проектах стандартные html формы которые на бек отправляют
KivApple
У формы есть onsubmit. По-хорошему, отправку делают обработкой этого события с preventDefault, а не через onclick кнопки. Так и Enter в полях будет работать привычным образом, и всякие средства автозаполнения, и утилиты для Accessibility.
anthonysnow887
Возможно я вас удивлю, но это много где встречается. Да хотя бы взять страницу входа (авторизации), почти везде используется отправка формы с типом "submit". Зачем изобретать велосипед, если "из коробки" все прекрасно работает? =)