data-атрибут

Data-атрибут – HTML-атрибут с префиксом data-*, валидный способ хранить произвольные данные в разметке любого элемента. В JavaScript доступен через element.dataset, в CSS – через селекторы [data-...] и функцию attr().

4 минуты чтения

По стандарту HTML любой атрибут, имя которого начинается с префикса data-, валиден на любом элементе. Это официальный ответ на давнюю потребность разработчиков: положить рядом с элементом служебную информацию – идентификатор, состояние, настройку компонента, – не изобретая нестандартные атрибуты и не пряча данные в имена классов. Браузер такие атрибуты не отображает и никак не интерпретирует: они существуют для скриптов, стилей и автотестов. В отличие от атрибутов ARIA, которые описывают элемент для вспомогательных технологий, data-* – канал «для себя»: разработчик сам решает, что и зачем там хранить.

Как это работает

Имя после префикса пишут в kebab-case: латиница в нижнем регистре, цифры, дефисы – data-user-id, data-index-number. Стандарт допускает также точку, двоеточие и подчёркивание, но на практике держатся kebab-case: именно дефис участвует в преобразовании имени для JavaScript. В JavaScript такие атрибуты доступны через свойство element.dataset – объект DOMStringMap, в котором префикс data- отброшен, а дефисы превращены в camelCase: data-index-number читается как dataset.indexNumber. Преобразование работает в обе стороны: запись el.dataset.someDataAttr = "x" создаёт в разметке атрибут data-some-data-attr="x", причём dataset и HTML синхронны – изменение одного сразу видно в другом.

<article id="post" data-columns="3" data-index-number="12314">...</article>
const article = document.querySelector("#post");

article.dataset.columns;      // "3" – всегда строка
article.dataset.indexNumber;  // "12314" (data-index-number → indexNumber)

article.dataset.columns = 5;  // запишет data-columns="5"
delete article.dataset.indexNumber; // удалит атрибут из HTML

Три правила, о которые спотыкаются чаще всего:

  • Значения – всегда строки. Число 42 станет строкой "42", null – строкой "null". Числа приводят через Number(), сложные структуры хранят как JSON-строку и разбирают через JSON.parse.
  • Проверка наличия – через 'columns' in el.dataset или сравнение с undefined: отсутствующий атрибут не бросает ошибку, а просто возвращает undefined.
  • Поиск по атрибутуdocument.querySelectorAll('[data-columns]') находит все элементы с таким атрибутом, а '[data-columns="3"]' – только с конкретным значением.

getAttribute и dataset – в чём разница

Сравнение dataset и getAttribute
Критерийelement.datasetgetAttribute / setAttribute
ИмяcamelCase без префикса: dataset.userIdКак в разметке: getAttribute("data-user-id")
ДоступОбъектный: чтение, запись, deleteТри отдельных метода: get, set, removeAttribute
Область примененияТолько data-атрибутыЛюбые атрибуты элемента
Когда выбиратьОсновная работа с data-*: читаемее и корочеИмена без преобразований, универсальный код

Для единичных обращений разница в производительности на практике не имеет значения – выбирают по читаемости кода.

Зачем это нужно

  • JS-хуки – скрипт находит элементы по data-атрибуту, а не по классу: классы остаются стилям, и правка вёрстки не ломает JavaScript. Отдельный случай – хуки для автотестов вида data-testid.
  • Параметры для обработчиков – при делегировании событий один слушатель на контейнере читает из dataset кликнутого элемента, с каким объектом работать: data-user-id="42" вместо отдельного обработчика на каждую кнопку.
  • Состояния и варианты для CSS – селекторы атрибутов вида [data-variant="warning"] заменяют россыпь модификаторов-классов, а content: attr(data-tooltip) выводит значение атрибута в псевдоэлементе – так делают чистые CSS-тултипы.
  • Мост между JS и CSS – например, скрипт определяет тёмную тему через window.matchMedia() и записывает результат в data-атрибут на корневом элементе, а стили реагируют селектором по этому атрибуту.

Когда data-атрибуты не подходят

Data-* – канал для служебных, а не смысловых данных. Скринридеры и другие вспомогательные технологии могут не иметь доступа к значениям data-атрибутов, поэтому видимый или важный по смыслу контент должен лежать в обычной разметке – это базовое правило доступности. Для описания элементов ассистивным технологиям есть отдельные атрибуты, например aria-label. Поисковые краулеры тоже могут не индексировать значения data-атрибутов – контент, который должен попасть в поиск, в них прятать нельзя. Наконец, data-атрибуты – не база данных: большие и сложные структуры держат в состоянии приложения или получают с сервера, а в разметке оставляют только ключи и короткие параметры.

Пример

Классика делегирования: список пользователей, у каждого кнопка «Открыть». Вместо обработчика на каждую кнопку – один на документе, а параметры лежат в разметке:

<button data-user-id="42">Открыть</button>
<button data-user-id="43">Открыть</button>
document.addEventListener("click", (e) => {
  const btn = e.target.closest("[data-user-id]");
  if (btn) {
    openUser(Number(btn.dataset.userId)); // dataset вернёт строку "42"
  }
});

CSS-часть – вариант оформления и тултип из атрибута:

.callout[data-variant="warning"] {
  border-color: rgb(235 15 15); /* значение селектора – в кавычках, даже число */
}

.hint::after {
  content: attr(data-tooltip);
}

На Битрикс-проектах data-атрибуты – основной способ передать данные из PHP-шаблона компонента в JavaScript: идентификаторы элементов инфоблока, параметры для целей Метрики, настройки слайдеров. Шаблон выводит атрибуты в вёрстку, скрипт читает dataset – без глобальных переменных и инлайн-скриптов на каждый элемент. Такой код переживает редизайн: пока имена data-атрибутов на месте, JS-логика не зависит от классов и структуры вёрстки, и правки дизайнера не превращаются в тикеты про сломанные скрипты.

Частые вопросы

Чем data-атрибуты отличаются от просто выдуманных атрибутов?

По стандарту HTML на любом элементе валидны только пользовательские атрибуты с префиксом data-. Атрибут с произвольным именем без префикса – нестандартная разметка: браузер её обычно переживёт, но валидатор укажет ошибку. Префикс data- гарантирует, что имя не столкнётся со стандартными атрибутами HTML.

Как прочитать data-атрибут в JavaScript?

Через element.dataset: атрибут data-index-number доступен как dataset.indexNumber – префикс отбрасывается, дефисы превращаются в camelCase. Альтернатива – element.getAttribute('data-index-number'), где имя пишется точно как в разметке.

Почему data-index-number читается как dataset.indexNumber?

dataset – объект DOMStringMap, который отображает имена по правилу: префикс data- отбрасывается, а каждая пара «дефис + строчная буква» превращается в заглавную букву (camelCase). При записи преобразование обратное: dataset.userId = '42' создаст в HTML атрибут data-user-id='42'.

Можно ли хранить в data-атрибуте число или объект?

Значение атрибута – всегда строка: число 42 при чтении вернётся как строка '42', null – как строка 'null'. Числа приводят через Number() или parseInt(), а объекты и массивы кладут в атрибут JSON-строкой и разбирают через JSON.parse. Для больших структур данных data-атрибуты не подходят.

Что лучше – dataset или getAttribute?

dataset удобнее при работе именно с data-атрибутами: объектный доступ, автоматический camelCase, удаление через delete. getAttribute универсален – работает с любыми атрибутами и не преобразует имена. Для единичных обращений разницы в производительности на практике нет, выбирают по читаемости кода.

Можно ли использовать data-атрибуты в CSS?

Да, двумя способами. Селекторы атрибутов вида [data-variant='warning'] стилизуют элемент по значению, причём значение пишется в кавычках даже для чисел. Функция attr() выводит значение в псевдоэлементе: content: attr(data-tooltip) – так делают чистые CSS-тултипы без JavaScript.

Когда data-атрибуты использовать нельзя?

Для видимого и смыслового контента: скринридеры могут не иметь доступа к значениям data-атрибутов, а поисковые краулеры – не индексировать их. Такие данные должны лежать в обычной разметке или в aria-атрибутах. Также data-атрибуты не подходят для больших объёмов и сложных структур данных – это не база данных.

Материалы по теме

Валентина Меланина

Нужна консультация?

Разберу ваш сайт и покажу точки роста

Если хотите понять, как этот термин применить к вашему проекту — начнём с аудита.