HTML-атрибуты
data-* позволяют хранить данные, непосредственно связанные с конкретным DOM-элементом. Для доступа к таким значениям DOM предоставляет стандартный API dataset.<button
data-user-id="42"
data-action="delete"
>
Удалить
</button>
Свойство
dataset возвращает объект DOMStringMap, через который можно читать значения data-* как свойства JavaScript-объекта.const button = document.querySelector('button');
console.log(button.dataset.userId);
// "42"
console.log(button.dataset.action);
// "delete"При формировании имени свойства префикс
data- удаляется, а дефис перед строчной ASCII-буквой a-z удаляется, при этом следующая буква преобразуется в верхний регистр. Поэтому data-user-role становится dataset.userRole.<div
id="user"
data-user-role="admin"
></div>
Это преобразование выполняется самим DOM API, поэтому обращаться к исходному имени атрибута вручную не требуется.
const user = document.querySelector('#user');
console.log(user.dataset.userRole);
// "admin"dataset поддерживает не только чтение. Присваивание свойства изменяет соответствующий data-* атрибут элемента.button.dataset.action = 'restore';
console.log(button.getAttribute('data-action'));
// "restore"
Если соответствующего
data-* атрибута ещё нет, присваивание через dataset создаст его в DOM.button.dataset.loading = 'true';
console.log(button.hasAttribute('data-loading'));
// true
Удаление свойства через оператор
delete удаляет и соответствующий атрибут элемента.delete button.dataset.loading;
console.log(button.hasAttribute('data-loading'));
// false
Важная особенность
dataset: значения представлены строками. При присваивании числа, boolean и другие значения преобразуются в строковое представление.button.dataset.userId = 42;
button.dataset.active = true;
console.log(button.dataset.userId);
// "42"
console.log(button.dataset.active);
// "true"
console.log(typeof button.dataset.userId);
// "string"
Если приложению нужен другой тип, преобразование следует выполнять явно. Это особенно важно для чисел и boolean-значений, поскольку строка
"false" в JavaScript сама по себе является truthy.const userId = Number(button.dataset.userId);
const isActive = button.dataset.active === 'true';
Один из практических сценариев для
data-* — делегирование событий. При этом использовать event.target.dataset напрямую не всегда корректно: фактической целью события может оказаться вложенный span, svg или другой дочерний элемент.<ul id="users">
<li>
<button data-user-id="42">
<span>Удалить</span>
</button>
</li>
</ul>
Для такого случая надёжнее найти ближайший подходящий элемент через
closest() и дополнительно проверить, что он относится к нужному контейнеру.const list = document.querySelector('#users');
list.addEventListener('click', event => {
const button =
event.target.closest('[data-user-id]');
if (!button || !list.contains(button)) {
return;
}
const userId =
Number(button.dataset.userId);
removeUser(userId);
});dataset хорошо подходит для небольших объёмов метаданных, принадлежащих конкретному DOM-элементу: идентификаторов, режимов, состояний интерфейса и параметров поведения. Для сложных объектов и полноценного состояния приложения
data-* использовать не стоит — DOM в таком случае фактически превращается в хранилище состояния, для которого существуют более подходящие структуры данных.button.dataset.userId = '42';
button.dataset.action = 'delete';
button.dataset.confirm = 'true';
dataset — стандартный DOM API поверх data-*, который делает работу с пользовательскими атрибутами короче и удобнее, но не обеспечивает типизацию их значений: значения dataset представлены строками и при необходимости требуют явного преобразования.

