Для чего делают кнопки, которые не отправляют формы
Что проверяют
Знаете ли вы, что у <button> без атрибута type значение по умолчанию submit, и понимаете ли, чем кнопка отличается от ссылки и от div с обработчиком. Следом обычно спрашивают про доступность: что потеряет пользователь клавиатуры или скринридера, если кнопку заменить на div.
Как отвечать
Кнопка это элемент для действия на странице, а отправка формы лишь одно из таких действий. Кнопки с type="button" нужны для всего остального:
- управление интерфейсом: открыть модальное окно, раскрыть аккордеон, показать пароль, переключить тему. Переключателю добавляют
aria-pressed, раскрывающему блокaria-expanded; - действия внутри формы без отправки: добавить ещё одно поле телефона, убрать выбранный файл, перейти к следующему шагу мастера после клиентской проверки;
- действия через JavaScript: запрос через
fetch, копирование в буфер обмена, запуск видео; - декларативные действия без JS: атрибут
popovertargetоткрывает элемент сpopover, а более новыеcommandforиcommandумеют, например, открыть<dialog>модально. Поддержку последних сверяйте с caniuse.
Почему именно <button>, а не div: кнопка получает фокус с клавиатуры, срабатывает по Enter и Space, объявляется скринридером как кнопка и уважает disabled. На div всё это придётся воспроизводить вручную через tabindex, role и обработчики клавиш, и обычно это делают не полностью.
Граница со ссылкой: если действие меняет адрес страницы, нужен <a href>. Ссылку можно открыть в новой вкладке и скопировать, кнопку нельзя.
Где спотыкаются
Забывают type="button" у кнопки внутри формы. «Показать пароль» начинает отправлять форму, и в React это выглядит как внезапная перезагрузка страницы или лишний запрос.
Не знают про неявную отправку: Enter в текстовом поле нажимает первую кнопку-submit формы. Если раньше основной стоит кнопка без type, сработает именно она.
Делают навигацию кнопкой, а действия ссылкой с href="#" и preventDefault. Для скринридера это разные роли, и путаница ломает ожидания пользователя.