Custom data-* Attributes
Attach your own structured data to any element, the standards-compliant way.
Sometimes you need to stash a bit of your own data on an element — a product id, a state flag, a config value. Inventing attributes like productid is invalid HTML. The sanctioned way is the data-* prefix.
The rules are simple
- Any attribute starting with
data-is valid:data-user-id,data-price,data-theme. - Read and write it from JavaScript through the
datasetproperty. - Names convert from kebab-case to camelCase:
data-user-idbecomeselement.dataset.userId.
<li data-id="42" data-price="9.99">Widget</li>
el.dataset.id // "42"
el.dataset.price // "9.99"Bonus: CSS can see them too
Attribute selectors like [data-state="open"] let you drive styling from your data without touching classes — handy for state machines and toggles.
Example
Loading editor…
Press Run to see the result.
When to use it
- A JavaScript event handler reads data-product-id from a clicked button to know which product to add to the cart.
- A CSS selector uses [data-theme="dark"] to apply a dark-mode palette without adding extra class names.
- A drag-and-drop list stores the item order in data-index on each element so the JS drop handler can reorder the array.
More examples
Data attribute read by JavaScript
dataset.productId maps camelCase to the hyphenated data-product-id attribute automatically.
<button class="add-to-cart"
data-product-id="42"
data-product-name="HTML Course"
data-price="29.00">
Add to cart
</button>
<script>
document.querySelector(".add-to-cart")
.addEventListener("click", function() {
const { productId, productName, price } = this.dataset;
console.log(`Adding ${productName} (id:${productId}) at $${price}`);
});
</script>Data attribute targeted by CSS
CSS attribute selectors can directly target data attributes for state-driven styling without class toggling.
<style>
[data-theme="dark"] {
background: #1a1a2e;
color: #eaeaea;
}
[data-status="error"] {
border: 2px solid red;
background: #fff0f0;
}
</style>
<div data-theme="dark">
<input data-status="error" type="text">
<p>Dark theme panel with error input.</p>
</div>Pagination links with data attributes
Storing page numbers in data-page lets a single handler serve all pagination links without inline onclick.
<nav aria-label="Pagination">
<a href="#" data-page="1" class="page-link">1</a>
<a href="#" data-page="2" class="page-link">2</a>
<a href="#" data-page="3" class="page-link">3</a>
</nav>
<script>
document.querySelectorAll(".page-link")
.forEach(link => link.addEventListener("click", e => {
e.preventDefault();
loadPage(e.target.dataset.page);
}));
function loadPage(page) {
console.log("Loading page", page);
}
</script>
Discussion