Store Custom Data on DOM Elements Safely

JavaScript permits “expando” properties such as element.myState on DOM objects. That is not automatically a security flaw, but it can collide with browser APIs or other scripts. Use an explicit storage mechanism instead.

Last updated: October 17, 2026.

const stateByElement = new WeakMap();
const button = document.querySelector('#saveButton');

button.dataset.action = 'save';
stateByElement.set(button, {
  pending: false,
  run: () => saveDocument()
});

button.addEventListener('click', () => {
  const state = stateByElement.get(button);
  if (!state.pending) state.run();
});

The data-action value is visible in HTML and always stored as a string. The object and callback stay outside the element in a WeakMap.

Choose storage based on visibility and type

Use dataset for short values that belong in markup, such as an action name or record identifier. Writes become data-* attributes and values are converted to strings. Treat them as untrusted input when they can be changed in developer tools or generated from user content.

Use a WeakMap for objects, functions, request state, and implementation details. The DOM element becomes the key, and the mapping does not prevent the element from being garbage-collected. Unlike a normal property, the state is not exposed by enumerating the element.

Understand the actual security boundary

Storing a function does not execute it; the risk appears when code later invokes a value from an untrusted source or writes untrusted text into an unsafe HTML sink. Never convert a string from dataset into code with eval() or new Function(). Map approved action names to functions you define.

Direct custom properties may be acceptable inside a small, fully controlled component, but use a Symbol to reduce naming collisions. Do not overwrite names such as onclick, remove, or browser-defined methods. Continue with running code after the DOM is ready, updating attribute-driven CSS, and tracing JavaScript failures.

Related Web Cheat Sheet guides

Sergey Kornilov

Sergey Kornilov