Data attribute

Also known as: data-* attribute

On this page 7

A data attribute, also written as a data-* attribute, is a custom HTML attribute whose name begins with `data-` and which stores private, page-specific information on an element, for example data-product-id="482". In HTML it is the standard, valid way to attach extra values for scripts and styles without inventing non-standard attributes or abusing classes and IDs.

Data attributes are ignored by the browser’s rendering and accessibility layers: they do not change how an element looks or what it means. Their value lies in being readable from JavaScript through the dataset property and selectable from CSS with attribute selectors, which makes them a lightweight bridge between markup, behavior and presentation.

Syntax and naming rules

The HTML Living Standard defines a custom data attribute as any attribute whose name starts with `data-` followed by at least one character. The name must be XML-compatible, must not contain uppercase ASCII letters, and must not begin with xml after the prefix. Values are always plain strings; numbers, booleans and lists must be encoded as text and parsed by the script that reads them.

The table below shows how attribute names in markup map to properties in the DOM.

Attribute in HTMLProperty in JavaScriptValue type read
`data-id`element.dataset.idString
`data-user-id`element.dataset.userIdString
`data-max-items`element.dataset.maxItemsString, parse to number
`data-is-open`element.dataset.isOpenString such as true or false
`data-config`element.dataset.configString, often JSON to parse
Mapping between markup names and dataset properties

The conversion follows a fixed rule: the `data-` prefix is removed and every hyphen followed by a lowercase letter becomes the uppercase version of that letter, producing camelCase. Setting element.dataset.maxItems = 10 performs the reverse and writes data-max-items="10" into the DOM.

Reading and writing data attributes

Scripts can access data attributes in two ways. The `dataset` property returns a live DOMStringMap with camelCase keys, while `getAttribute` and `setAttribute` use the full hyphenated name. Both read and change the same underlying attribute, so the choice is mainly about readability and consistency within a codebase.

CSS can use the same attributes in two ways. Attribute selectors such as [data-state="open"] apply styles based on a value, which is a clean way to express component state. The attr() function can display a value in generated content, for example a tooltip label in a pseudo-element, although broad support for using attr() in other properties is still limited.

TechniqueExampleTypical purpose
dataset readbutton.dataset.actionChoose behavior in an event handler
dataset writepanel.dataset.state = "open"Expose component state to CSS
Attribute selector[data-variant="primary"]Style variants without extra classes
Query selectorquerySelectorAll("[data-track]")Find elements for analytics or tests
attr() in contentcontent: attr(data-label)Show a value in generated content
Ways to work with data attributes

Data attributes compared with other ways to store information

Data attributes overlap with classes, IDs, ARIA attributes and JavaScript objects, but each mechanism has a distinct responsibility. Mixing them leads to brittle code, for example styles breaking when a test hook is renamed, or accessibility depending on a value that assistive technology never reads.

MechanismPrimary roleUse it forAvoid it for
Data attributePrivate custom valuesScript hooks, state, test IDsMeaning or accessibility
ClassStyling categoriesReusable visual stylesStoring values
IDUnique identificationFragment links, label associationRepeated elements
ARIA attributeAccessibility semanticsStates such as aria-expandedArbitrary application data
JavaScript stateIn-memory dataLarge or sensitive dataValues CSS must react to
Choosing the right mechanism

A practical pattern combines them: an accordion button uses `aria-expanded` to communicate state to screen readers and a `data-state` attribute, or the ARIA attribute itself, for styling. When an ARIA attribute already expresses the state, styling it directly avoids duplicated and potentially inconsistent state.

Common uses in web development

Data attributes are widespread because they keep configuration close to the markup that needs it. Server-rendered pages can embed values that client scripts pick up without extra network requests, and frameworks and libraries use them for initialization and hydration.

  • Behavior hooks: data-action="delete" lets one event listener handle many buttons through event delegation.
  • Test selectors: data-testid gives end-to-end tests a stable target that does not change with styling.
  • Analytics: data-track attributes mark elements whose interactions should be recorded.
  • Component configuration: carousels, modals and charts read options such as interval or theme from data attributes.
  • State for styling: values such as data-state="loading" drive CSS transitions without class juggling.

Limitations and mistakes to avoid

Because data attributes are visible in the page source and the DOM, they must never contain secrets such as tokens, personal data or internal pricing rules. They are also not indexed for meaning by search engines and not exposed to assistive technology, so content that users need must appear as visible text or proper semantic HTML.

ProblemConsequenceFix
Sensitive data in attributesExposed to anyone viewing sourceKeep it on the server or in memory
Uppercase in namesLowercased by the parser, lookup failsUse lowercase, hyphen-separated names
Large JSON blobsBloated HTML, slow parsingUse a script data block or an API
Meaning only in data attributesInvisible to screen readersUse semantic elements and ARIA
Treating values as numbersString comparison bugsParse explicitly before calculating
Frequent problems and fixes

The simple explanation

A data attribute is like a small sticky note attached to a part of a web page. Visitors do not see it, but the code running the page can read it. For example, a button might carry a note with the number of the product it adds to the cart.

This keeps information right where it is needed. Developers do not have to keep it somewhere else. The important rule is to never put secrets on these notes. Anyone who opens the page code can read them.

How it is used in practice

An online bookstore lists 24 books per page, each with an Add to cart button. Instead of attaching 24 separate event listeners, the developer gives every button a data-action="add-to-cart" and a data-isbn value, then adds one delegated click listener on the product list that reads event.target.dataset.isbn and sends it to the cart API.

While the request runs, the script sets data-state="loading" on the button, and a CSS rule targeting that value shows a spinner and disables pointer events. The QA team targets the same buttons through stable data-testid values. The result is less JavaScript, clear state styling and end-to-end tests that no longer break after visual redesigns.