Himanshu SharmaSoftware engineer
Let’s talk

jQuery · Lesson 16 of 45

Storing data on elements with .data()

Read data- attributes with jQuery .data(), see how names and values are converted, store your own values on elements, and know when .attr() is better.

11 minReading and changing the pageUpdated 23 October 2026

By the end of this lessonUse data- attributes to pass information from HTML to your code, and attach values to elements without touching the page markup.

Data attributes

HTML lets you add your own attributes as long as their names start with data-. They are a clean way to give your scripts information without hiding it in classes or ids:

html
<button class="add" data-product-id="42" data-price="1200" data-in-stock="true">Add to cart</button>

Browsers ignore these attributes, CSS can read them, and JavaScript can read them. jQuery's .data() makes reading them convenient.

Reading with .data()

html
<button id="buy" data-product-id="42" data-price="1200.50" data-in-stock="true" data-tags='["desk","oak"]' data-name="Oak desk">Buy</button>

<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
  const $b = $("#buy");
  console.log("productId:", $b.data("productId"), typeof $b.data("productId"));
  console.log("price:", $b.data("price"), typeof $b.data("price"));
  console.log("inStock:", $b.data("inStock"), typeof $b.data("inStock"));
  console.log("tags:", $b.data("tags").length, "tags, first is", $b.data("tags")[0]);
  console.log("name:", $b.data("name"));
  console.log("all:", JSON.stringify($b.data()));
</script>
result
productId: 42 number
price: 1200.50 string
inStock: true boolean
tags: 2 tags, first is desk
name: Oak desk
all: {"productId":42,"price":"1200.50","inStock":true,"tags":["desk","oak"],"name":"Oak desk"}

Two things happen automatically:

  1. Names become camelCase. data-product-id is read as productId, data-in-stock as inStock.
  2. Values are converted. Strings that look like numbers become numbers, "true" and "false" become booleans, "null" becomes null, and text that looks like a JSON object or array is parsed.

With no argument, .data() returns an object containing every data value of the element. Look at the price, though: it stayed a string. The next section explains why.

When conversion does not happen

jQuery only turns a string into a number if turning it back gives exactly the same string. This protects values that look like numbers but are not:

html
<span id="s" data-zip="007" data-price="1.50" data-code="12" data-big="1e3"></span>

<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
  const $s = $("#s");
  for (const key of ["zip", "price", "code", "big"]) {
    console.log(key, JSON.stringify($s.data(key)), typeof $s.data(key));
  }
</script>
result
zip "007" string
price "1.50" string
code 12 number
big "1e3" string

"007" and "1.50" stay strings, because as numbers they would become 7 and 1.5. "12" becomes the number 12. If you need a value to be a number every time, convert it yourself with Number(); if you need the exact text, read it with .attr().

Using data attributes in a handler

Data attributes shine when many elements share one click handler:

html
<div>
  <button data-product-id="7" data-name="Desk lamp" data-price="1200">Add lamp</button>
  <button data-product-id="9" data-name="Notebook" data-price="150">Add notebook</button>
</div>
<p id="cart">Cart is empty</p>

<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
  $("button").on("click", function () {
    const item = $(this).data();
    $("#cart").text("Added " + item.name + " (#" + item.productId + ") for " + item.price);
    console.log(item.productId + item.price);
  });
</script>
result
159

The logged sum shows that productId and price really are numbers: 9 + 150 = 159, not the string "9150".

Storing your own values

.data(key, value) attaches any JavaScript value to an element: numbers, objects, even functions. It is kept in jQuery's internal memory, not in the HTML:

html
<div id="widget" data-status="new">Widget</div>

<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
  const $w = $("#widget");
  $w.data("status", "saved");
  $w.data("settings", { theme: "dark", size: 3 });

  console.log("data status:", $w.data("status"));
  console.log("attr status:", $w.attr("data-status"));
  console.log("settings size:", $w.data("settings").size);

  $w.removeData("status");
  console.log("after removeData:", $w.data("status"));
</script>
result
data status: saved
attr status: new
settings size: 3
after removeData: new

Notice three things:

  • After setting status to saved, the attribute still says new. .data() does not write to the HTML.
  • jQuery reads the attribute only the first time; after that, it uses its stored value.
  • .removeData("status") deletes the stored value, so the next read falls back to the attribute again.

.data() or .attr()?

Situation Use
Reading configuration from HTML as real types .data()
Keeping state for an element in your script .data(key, value)
A CSS rule depends on the attribute, e.g. [data-state="open"] .attr("data-state", "open")
You need the exact string, e.g. a code with leading zeros .attr("data-code")

The plain JavaScript equivalent is the dataset property: element.dataset.productId. It always returns strings, and setting it does update the attribute.

Common mistakes

  • Expecting .data(key, value) to change the attribute and CSS selectors that use it.
  • Changing the attribute with .attr() after .data() has read it, then reading .data() again and getting the old value.
  • Relying on automatic conversion for codes, phone numbers and postcodes.
  • Using hyphenated keys inconsistently. Pick camelCase in your code.

Exercise

Give three list items a data-rating from 1 to 5. Use .data() to find the item with the highest rating and make it bold.

Show one possible answer
html
<ul><li data-rating="3">Lamp</li><li data-rating="5">Desk</li><li data-rating="4">Chair</li></ul>

<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
  let $best = $();
  $("li").each(function () {
    if (!$best.length || $(this).data("rating") > $best.data("rating")) $best = $(this);
  });
  $best.css("font-weight", "bold");
  console.log($best.text());
</script>
result
Desk

$() with no argument creates an empty selection, a handy starting value.

Key points

  • HTML data- attributes such as data-product-id hold extra information for your scripts.
  • .data("productId") reads data-product-id and converts numbers, true/false and JSON into real values.
  • .data(key, value) stores a value in jQuery's memory; it does not change the HTML attribute.
  • Use .attr("data-...") when you need the exact string, or when CSS or other code reads the attribute.

Check yourself

1. Which call reads the attribute data-user-id?
2. What does .data("count") return for data-count="12"?
3. After $(el).data("status", "done"), what does $(el).attr("data-status") return?
4. Why might .data("zip") on data-zip="007" surprise you?