Data-атрибуты - это способ прикрепить к обычному HTML-тегу любые свои данные, не трогая его содержимое и не выдумывая несуществующие атрибуты. Имя всегда начинается с data- и пишется строчными буквами через дефис: data-user-id="42". Прочитать значение можно в JavaScript через element.dataset.userId (дефис автоматически превращается в camelCase) или прямо в CSS через [data-user-id="42"] - без единой лишней переменной или таблицы соответствий.
В этом уроке
Каждая кнопка фильтра хранит свою категорию в data-filter, а каждая карточка - в data-category. Клик по кнопке просто сравнивает два data-атрибута между собой. Попробуй добавить ещё одну карточку с data-category="css" - она сразу же начнёт правильно показываться и скрываться вместе с остальными карточками той же категории.
Зачем нужны data-атрибуты в HTML: как хранить произвольные данные в разметке
До того как в HTML5 закрепили префикс data-, разработчики иногда просто дописывали к тегам собственные, ничем не предусмотренные атрибуты - это работало в браузере (он не проверяет атрибуты на валидность), но было технически невалидно и рискованно: такое имя могло случайно совпасть с настоящим атрибутом, который появится в будущей версии HTML. Префикс data- решает это раз и навсегда - вся эта область имён официально зарезервирована только для собственных данных страницы и никогда не будет занята стандартным атрибутом.
<li data-user-id="42">Иван</li> - имя атрибута строчными буквами через дефис, как требует спецификация.
<li data-password="qwerty123">Иван</li> - значение атрибута видно любому, кто откроет исходный код страницы: данные для входа в data-атрибуте хранить нельзя.
<h1 src="что-то.gif"> - атрибут src никогда не был частью тега h1. Арье Грегор ответил, что это ошибка именно валидатора: по уже действовавшему тогда черновику HTML5 собственные атрибуты обязаны иметь префикс "data-", и правильный валидатор (validator.nu) на тот момент такой код уже отклонял. Источник.
Dataset API в HTML: как читать data-атрибуты через JavaScript и CSS
В JavaScript все data-атрибуты элемента доступны через свойство element.dataset - часть имени после "data-" автоматически превращается в camelCase: data-user-id становится dataset.userId. Важная деталь: значение всегда приходит СТРОКОЙ, даже если в разметке написано число - для реальных вычислений его нужно самостоятельно преобразовать через Number() (а для сложных структур - через JSON.parse()). В CSS то же самое значение доступно без единой строчки JavaScript - через атрибутный селектор [data-user-id="42"] или функцию attr() в generated content.
card.dataset.category === 'css' - сравнение строки со строкой, работает предсказуемо.
card.dataset.count + 1 при data-count="5" - вместо ожидаемого числа 6 получится строка "51": dataset.count вернул строку "5", а плюс со строкой - это склеивание, а не сложение.
Частые ошибки новичков
| Ошибка | Что происходит | Как исправить |
|---|---|---|
| Хранить в data-атрибуте пароль, токен или другие личные данные | Значение видно в исходном коде страницы любому, кто откроет "Просмотр кода" | Хранить чувствительные данные только на сервере, никогда в разметке |
| Прятать в data-атрибуте текст, который должен быть виден и доступен | Скринридер может не прочитать содержимое data-атрибута - контент выпадает из доступности | Видимый и значимый текст размещать в обычном содержимом тега, а не в атрибуте |
| Писать имя атрибута с заглавными буквами (data-userID) | Браузер при разборе приводит имя атрибута к нижнему регистру - получится dataset.userid, а не dataset.userID | Писать имя атрибута только строчными буквами через дефис: data-user-id |
| Забыть, что dataset всегда возвращает строку | Арифметика вроде dataset.count + 1 превращается в склеивание строк вместо сложения чисел | Преобразовывать значение вручную: Number(dataset.count) для чисел, JSON.parse() для сложных структур |
Шпаргалка
| Термин | Что это |
|---|---|
| data-* | Собственный атрибут для хранения любых данных прямо в теге |
| Имя атрибута | Только строчные буквы и дефисы: data-user-id, не data-userID |
| element.dataset.name | Доступ из JavaScript - дефисы автоматически становятся camelCase |
| [data-name="value"] | Доступ из CSS через атрибутный селектор, без JavaScript |
| Тип значения | Всегда строка - для чисел и объектов нужно преобразование вручную |
Коротко: отвечаем на вопросы
Можно ли хранить в data-атрибуте пароли или токены?
Нет. Как прямо предупреждает документация MDN, data-атрибуты не защищены и не скрыты - их значение видно в исходном коде страницы любому, кто откроет инструменты разработчика или Просмотр кода.
Почему раньше нельзя было просто придумать свой атрибут для тега?
Технически браузер и раньше не проверял атрибуты на валидность и всё равно отображал страницу. Но такой атрибут был невалиден и мог случайно совпасть с настоящим атрибутом из будущей версии HTML - это реально обсуждалось в переписке разработчиков WHATWG в ноябре 2009 года, когда только закреплялось правило про обязательный префикс data-.
Всегда ли data-атрибут возвращает строку в JavaScript?
Да, всегда. Даже если в разметке написано число, dataset вернёт его как строку - для вычислений нужно вручную преобразовать значение через Number(), а для сложных структур - через JSON.parse().
Сработает ли dataset.userID для атрибута data-user-ID?
Нет. Браузер приводит имя атрибута к нижнему регистру ещё при разборе страницы, поэтому data-user-ID превращается в dataset.userid, а не dataset.userID. Чтобы не путаться, имя атрибута стоит сразу писать строчными буквами: data-user-id.