dataset in JavaScript: reading and writing the data-* attributes of an element

dataset gives access to the data-* attributes of an HTML element: how names convert, why everything in it is a string, and its role in event delegation.
3 min read
Believemy logo

A table row displays an order, and the button that deletes it has to know its identifier. Where should that piece of information live without leaving the HTML?

The language provides an official place for it: data-* attributes, readable from JavaScript through a single property.


Definition

dataset is a property present on every HTML element, giving access to its attributes starting with data-. Each attribute shows up as a key there, readable and writable like the key of a plain Object.

JAVASCRIPT
// <li data-id="42" data-status="paid" data-sent-on="2026-03-14">

const row = document.querySelector("li");

console.log(row.dataset.id);       // "42"
console.log(row.dataset.status);   // "paid"
console.log(row.dataset.sentOn);   // "2026-03-14"

row.dataset.status = "refunded";   // updates the attribute in the HTML


How names convert

The prefix disappears, and each dash followed by a letter becomes a capital. The mapping is mechanical in both directions.

HTML attributeJavaScript key
data-iddataset.id
data-user-iddataset.userId
data-price-before-taxdataset.priceBeforeTax

Writing dataset.totalPrice therefore creates a data-total-price attribute, visible in the browser inspector.


Everything in it is a string

An HTML attribute only stores text. The value read back is always a String, even when it looks like a number or a boolean, and that is the most common source of error.

JAVASCRIPT
// <div data-quantity="3" data-active="false">

const block = document.querySelector("div");

console.log(block.dataset.quantity + 1);           // "31"
console.log(Number(block.dataset.quantity) + 1);   // 4

if (block.dataset.active) console.log("runs anyway");

The last line runs because the string "false" sits on the truthy side, as covered in Truthy and falsy. Compare explicitly, with === "true", rather than trusting the direct test.


The companion of delegation

Event delegation is where this property truly pays off: the single listener locates the element that was clicked, then reads from it the identifier to work on.

JAVASCRIPT
table.addEventListener("click", (event) => {
  const button = event.target.closest("[data-id]");
  if (!button) return;

  console.log("delete order", button.dataset.id);
});


Frequently asked questions

Question

Why not invent a homemade attribute?

An attribute such as orderid makes the document invalid, never shows up in dataset, and may collide with a standardized attribute later on. The data- prefix is reserved for exactly these application-specific needs.


Question

Can an object be stored in it?

Only as text, for instance through JSON on the way in and on the way out. That stays acceptable for a couple of fields and grows heavy beyond. To tie rich data to an element, a WeakMap or a Map kept in memory fits better.


Question

Can the visitor see these values?

Yes, and change them. A data-* attribute sits in the HTML sent to the browser and can be edited in two clicks in the inspector. No price, no role and no permission stored there may be treated as trustworthy: the server checks again every time.

Related terms

Discover our javaScript glossary

Every word of JavaScript explained simply: keywords, built-in objects, methods, errors and concepts. Clear definitions and examples that actually run, to learn and to troubleshoot.

Share this article

Want to help us? Share this article on your networks or even better: on your site, in an article or in your newsletter.