← На главную

Кастомная кнопка: 500 строк JS, но уступает нативной

16.07.2026 03:48 · hackernews

Пересоздавать нативные HTML-элементы с нуля — почти всегда плохая идея. Автор статьи разбирает это на примере кастомной кнопки <sagan-button> и показывает, насколько это сизифов труд.

Сначала кажется просто: добавил role="button", повесил tabindex="0", и вот уже элемент виден в accessibility tree и доступен с клавиатуры. Но дальше начинается ад. Нужно обработать клик мыши, касание, стилус — отдельно. Потом клавиши Space и Enter, причём с разной логикой. Уже на этом этапе код заметно разрастается.

Дальше — атрибуты. disabled тянет за собой ariaDisabled, CSS-состояние --disabled и синхронизацию через attributeChangedCallback. А ведь у нативного <button> есть ещё куча form-атрибутов: type, form, formaction, formmethod, formenctype, formnovalidate, formtarget, плюс name и value. Для каждого нужно писать геттер, сеттер и логику валидации. И это не считая Validation API: validity, validationMessage, willValidate, checkValidity, reportValidity, setCustomValidity.

Чтобы кнопка корректно работала с формами, нужно выставить formAssociated = true и подключать ElementInternals. А ещё автор разбирает порядок срабатывания событий: собственный обработчик должен выполняться до и после всех пользовательских, иначе preventDefault может сломаться. Для этого приходится оборачивать addEventListener.

Отдельная боль — атрибуты-обработчики вроде onmouseup. Они принимают строку, которую нужно распарсить как функцию через new Function — сомнительная практика, но иначе никак.

Автор сознательно пропустил поддержку Popover API, Invoker Commands API и экспериментального Interest Invoker API — иначе пост раздулся бы ещё сильнее. Итог: почти 500 строк JavaScript для кнопки, которая всё равно не дотягивает до нативной по функциональности. У нативного <button> этих строк — ноль.

Вывод: используйте семантический HTML. Даже если дизайнер просит что-то нестандартное, лучше переубедить его или найти другой паттерн. Современные браузеры позволяют стилизовать элементы достаточно гибко, а кастомные компоненты почти всегда ломают ожидания пользователей и accessibility. К тому же недоступные сайты — это риск судебных исков. А LLM по умолчанию генерируют недоступный код, но существуют решения и для этой проблемы.

Читать оригинал →