javascript

Просто используй кнопку

  • понедельник, 3 ноября 2025 г. в 00:00:06
https://habr.com/ru/articles/962632/

Мне часто доводится вести странные споры с фанатами фреймворков о том, действительно ли <div> «столь же хорош», как и <button>.

Спойлер: нет. И давайте выясним, почему.

Проблема

В среде разработчиков на React, а также у тех, кому нравится HTMX, я часто вижу такое…

<div onclick="showSignIn()">
	Open Modal
</div>
function showSignIn () {
	// Код для отображения модального окна входа.
	// Подробности реализации зависят от стека.
}

Что здесь не так?

  1. Этот элемент не сообщает о себе как об интерактивном элементе пользователям программ для чтения экрана.

  2. Нельзя получить фокус <div> с клавиатуры.

  3. Событие срабатывает только по click, но не при нажатии на клавиши Enter или пробел (клавиатурные пользователи снова страдают).

Я встречал такое во многих кодовых базах. И во многих демо.

Я спорил с очень известным идейным лидером React, имя которого начинается на Р: он настаивал, что <div> обеспечивает «бóльшую accessibility», чем <button>, и что команда Twitter приняла правильное решение, когда стала использовать этот паттерн в своём приложении.

Всё это совсем-совсем неправильно.

«Исправления», которые не исправления

Многие HTML-элементы имеют собственные роли, сообщающие вспомогательным приложениям, например, программам для чтения экрана, что они делают.

Элемент <button> — один из них. У него есть внутренняя [роль] кнопки, и это даёт пользователям программ чтения экрана понять, что с ним можно взаимодействовать и вызывать некое поведение в приложении.

HTML-атрибут [role] можно использовать для добавления и изменения роли элемента. Поэтому люди вроде Рай... лидера мнений React говорят что-то подобное (передаю общий смысл)…

Этот атрибут существует не просто так, можно добавить [role="button"] к div, чтобы придать ему корректную семантику.

Допустим, но это решает только одну проблему.

Эта роль не влияет на возможность фокусировки (или её отсутствие) и клавиатурное поведение. Пользователи с нарушением зрения, выполняющие навигацию с клавиатуры, всё равно не могут ею воспользоваться.

Вам скажут: «Не волнуйтесь! Это тоже можно исправить!»

Можно добавить элементу возможность фокусировки при помощи атрибута [tabindex].

<div 
	onclick="showSignIn()"
	tabindex="0"
>
	Open Modal
</div>

Однако делать этого не стоит! Серьёзно, не надо вмешиваться в порядок фокусировки.

Слишком легко пойти по этому пути, а затем всё поломать, из-за чего пользователи будут скакать по всей странице вместо того, чтобы двигаться по ней в обычном и предсказуемом порядке.

И опять-таки, интерактивность с клавиатуры всё ещё отсутствует.

Но не беспокойтесь! Можно и её добавить. Достаточно просто слушать все события keydown, а затем фильтровать их по event.key , чтобы код выполнялся только при нажатии на Enter или пробел (последнее означает проверку на буквальный пробел: ' ').

Но этот код нельзя выполнять и на элементе. Нужно прикрепить это событие к document и разбираться, у какого элемента есть фокус.

document.addEventListener('keydown', (event) => {

	// Выполняем только при нажатии на Enter и пробел
	if (event.key !== 'Enter' & event.key !== ' ') return;

	// Проверяем, что фокус на элементе, который нам нужен
	const notRealBtn = document.activeElement.closest('[onclick]');
	if (!notRealBtn) return;

	// Каким-то образом выполняем наш код...

});

Хм... допустим, строго говоря, так мы устранили проблему, но...

Так мы просто воссоздали всю функциональность, которая и так имелась

Серьёзно: на кой чёрт нам всё это делать?!?

Вся эта возня ради того, чтобы написать такой HTML…

<div 
	onclick="showSignIn()"
	tabindex="0"
>
	Open Modal
</div>

Когда можно просто написать так:

<button onclick="showSignIn()">
	Open Modal
</button>

У <button>

  1. Изначально имеется нужная [role].

  2. Есть автоматическая возможность фокусировки.

  3. Запускается событие click в ответ на нажатия Enter и Spacebar, если кнопка находится в фокусе.

Послушайте, я ленивый разработчик.

И, подозреваю, если вы любите инструменты наподобие React, то, вероятно, вы тоже ленивы. И это здорово! Лучший код — это код ненаписанный, и всё такое прочее.

Так что будьте ещё ленивее.

Используйте для этой задачи идеально подходящий элемент, ведь тогда вам не придётся писать кучу лишнего кода!