
Мне часто доводится вести странные споры с фанатами фреймворков о том, действительно ли <div> «столь же хорош», как и <button>.
Спойлер: нет. И давайте выясним, почему.
Проблема
В среде разработчиков на React, а также у тех, кому нравится HTMX, я часто вижу такое…
<div onclick="showSignIn()">
Open Modal
</div>
function showSignIn () {
// Код для отображения модального окна входа.
// Подробности реализации зависят от стека.
}
Что здесь не так?
Этот элемент не сообщает о себе как об интерактивном элементе пользователям программ для чтения экрана.
Нельзя получить фокус
<div>с клавиатуры.Событие срабатывает только по
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>…
Изначально имеется нужная
[role].Есть автоматическая возможность фокусировки.
Запускается событие
clickв ответ на нажатияEnterиSpacebar, если кнопка находится в фокусе.
Послушайте, я ленивый разработчик.
И, подозреваю, если вы любите инструменты наподобие React, то, вероятно, вы тоже ленивы. И это здорово! Лучший код — это код ненаписанный, и всё такое прочее.
Так что будьте ещё ленивее.
Используйте для этой задачи идеально подходящий элемент, ведь тогда вам не придётся писать кучу лишнего кода!
Комментарии (14)

nin-jin
02.11.2025 10:38можно добавить
[role="button"]А можно
role="tab"не надо вмешиваться в порядок фокусировки.
tabindex="0"и не влияет на порядок.Нужно прикрепить это событие к
documentНе нужно.

moscowman
02.11.2025 10:38Меня лично бесит, когда табом или аддоном Surfingkeys нельзя добраться до какого-то элемента формы и приходится переносить руки на мышь.
Так лежат руки на месте и лежат, очень удобно и быстро, а тут туда-сюда, прицелься и тыкни.

SWATOPLUS
02.11.2025 10:38Это все берется из-за магии тегов, потому что навешиваются доп. стили, которые могут вылезти неожиданно в каком-нибудь браузере.
Например есть вот эта таблица c дефолтными стилями: https://www.w3schools.com/cssref/css_default_values.php
a:link color: (internal value);
Этот (internal value) может различаться в браузерах, а хочется что бы было все единообразно.
Плюс эта таблица не раскрывает aria-атрибуты и читалка может по разному работать в разных браузерах, и поэтому приходиться ручками что-то дописывать.И вот тут приходит мысль использовать div, самому все прописать и радоваться, что все везде одинаково работает. Но див не панацея, и самая частая задача где он не подходит это router-link. Казалось бы прописал на onclick смену роута, aria и все хорошо, но не работает функция открыть в новой вкладке. Поэтому приходиться использовать a-tag, делать preventDefault и переписывать стили.
Еще бывает когда используют
<a href="#" />для открывания модалки, но такая кнопка скролит в начало документа. Поэтому надоhref="javascript:void(0)"или preventDefault, или вообще button.В общем, что бы все работало красиво с a11y и единообразными стилями, нужно знать много тонкостей, а хочется быстро и просто.
Что бы лично я мог предложить:
Резервирование тега e (element) в HTML и гарантирование отсутствия каких либо aria, стилей и всего остального.
Введение дополнительных атрибутов, которые позволяют превратить e-тег в любой другой элемент например urlforopeninnewtab (попмини что все стандартные атрибуты пишутся без разделителей).
Стандартизация всех тегов, составления списка стилей (уже есть), aria и других атрибутов, которые применяются по умолчанию.
Тогда можно будет почитать этот список и понять, что же нужно будет переопределить для требуемого эффекта.

nin-jin
02.11.2025 10:38приходиться использовать a-tag, делать preventDefault и переписывать стили
Надо сформировать корректный целевой урл, позволить пользователю по нему перейти любым удобным способом, и отреагировать изменением интерфейса на изменение урла, каким бы образом он ни поменялся. Но я, конечно, оторван от современной разработки, я не умею кодить через то место, через которое выходит говнокод.

muxa_ru
02.11.2025 10:38Этот (internal value) может различаться в браузерах, а хочется что бы было все единообразно.
Согласен, пользователям хочется чтобы было всё однообразно, чтобы в том браузере которым они пользуются, на всех сайтах ссылки были раскрашены одинаковым цветом.
Вы ведь про это однообразие говорили?
navferty
Так и не понял, а в чём состоит аргументация тех, кто агитирует за использование div вместо button?
nin-jin
Нет необходимости делать ресет стандартных стилей.
Стабильная кроссбраузерная стилизация без неожиданных сдвигов на пару пикселей.
Нет неожиданной отправки формы любой кнопкой в ней.
Можно реиспользовать тот же компонент кнопки для релизации и других кликабельных контролов.
vanxant
так не надо лепить тип submit и не будет никаких отправок
А кто сейчас не делает ресет стандартных стилей?
dominus_augustus
Читаю когда ответы создателя лучшего фреймворка не покидает ощущение его оторванности от современной разработки
nin-jin
https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/button#type
Тот, кто не хочет неожиданных сайд эффектов.
muxa_ru
Полагаю, это стандартная аргументация "я подсмотрел в интернете вот такой вариант, по другому не умею и теперь весь мир должен под меня подстроиться."