Question

How to Get a data-id Attribute in jQuery

htmljavascriptjquerycustom-data-attribute

Question

I am using the jQuery Quicksand plugin and need to read the data-id value from a clicked list item, then pass that value to a web service.

How can I correctly get the data-id attribute?

I am rebinding the click event with .on() because the items are sorted dynamically.

$("#list li").on('click', function() {
  // ret = DetailsView.GetProject($(this).attr("#data-id"), OnComplete, OnTimeOut, OnError);
  alert($(this).attr("#data-id"));
});
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>

<ul id="list" class="grid">
  <li data-id="id-40" class="win">
    <a id="ctl00_cphBody_ListView1_ctrl0_SelectButton" class="project" href="#">
      <img src="themes/clean/images/win.jpg" class="project-image" alt="get data-id" />
    </a>
  </li>
</ul>

Short Answer

By the end of this page, you will understand how to read custom data-* attributes in jQuery, when to use .attr() versus .data(), and how to attach click handlers correctly for dynamically updated elements.

Concept

Custom data-* attributes let you store extra information directly on HTML elements. In your example, the li element stores a project identifier in data-id:

<li data-id="id-40"></li>

In jQuery, you can read this value in two common ways:

$(this).attr('data-id')
$(this).data('id')

The main issue in the original code is this part:

$(this).attr("#data-id")

That is incorrect because .attr() expects the attribute name only, not a CSS selector. The correct attribute name is data-id, not #data-id.

Why this matters:

  • data-* attributes are widely used for IDs, flags, categories, and configuration.
  • They help connect HTML elements to JavaScript behavior.
  • They are especially useful in lists, buttons, cards, and dynamically generated UI items.

If elements are replaced or sorted dynamically, direct event binding may stop working. In those cases, event delegation with .on() is often the safest approach.

Mental Model

Think of an HTML element as a labeled storage box.

  • The element itself is the box.
  • Normal attributes like id, class, and href are built-in labels.
  • data-* attributes are your own extra sticky notes.

So this element:

<li data-id="id-40"></li>

is like a box with a note that says:

  • data-id = id-40

When a user clicks the element, jQuery lets you open the box and read that note.

Take Quiz

Syntax and Examples

The two most common ways to read a data-id value in jQuery are:

$(this).attr('data-id')
$(this).data('id')

Basic example

$("#list li").on("click", function () {
  alert($(this).attr("data-id"));
});

This reads the data-id attribute from the clicked li.

Using .data()

$("#list li").on("click", function () {
  alert($(this).data("id"));
});

This also works and is often cleaner when working with data-* attributes.

Better for dynamically changed items: delegated event binding

If items are re-rendered, sorted, or replaced, use delegated events:

$("#list").on("click", "li", function () {
  const projectId = $(this).data("id");
  alert(projectId);
});

This attaches the event handler to #list, and jQuery listens for clicks that bubble up from any li inside it.

Passing the value to a function

$("#list").on("click", "li", function () {
  const projectId = $(this).data("id");
  DetailsView.GetProject(projectId, OnComplete, OnTimeOut, OnError);
});

This is the common real-world pattern: read a value from the clicked element, then use it in an API or service call.

Step by Step Execution

Consider this code:

$("#list").on("click", "li", function () {
  const projectId = $(this).data("id");
  alert(projectId);
});

And this HTML:

<ul id="list">
  <li data-id="id-40">Project A</li>
</ul>

Here is what happens step by step:

  1. jQuery attaches one click listener to #list.
  2. You click on the li element.
  3. The click event bubbles up to #list.
  4. jQuery checks whether the clicked target matches the selector li.
  5. Since it does match, the handler runs.
  6. Inside the handler, this refers to the clicked li.
  7. $(this).data("id") reads the value from data-id.
  8. The value id-40 is stored in projectId.
  9. alert(projectId) shows id-40.

Trace:

  • Clicked element: li
  • this: clicked li
  • $(this).data("id"): "id-40"
  • Result: alert shows id-40

Real World Use Cases

data-* attributes are very common in real applications.

Common uses

  • Storing a database record ID on a row or card
  • Attaching product IDs to "Add to cart" buttons
  • Keeping category names for filtering items
  • Marking elements with status flags like data-active="true"
  • Passing small configuration values from HTML to JavaScript

Example: product card

<button class="add-to-cart" data-product-id="101">Add to cart</button>
$(document).on("click", ".add-to-cart", function () {
  const productId = $(this).data("product-id");
  console.log("Add product", productId);
});

Example: table row actions

<tr data-user-id="55">
  <td>Alice</td>
  <td><button class="view-user">View</button></td>
</tr>
$(document).on("click", ".view-user", function () {
  const userId = $(this).closest("tr").data("user-id");
  console.log("Load user", userId);
});

This pattern is useful when the clicked element is inside another element that holds the data.

Take Quiz

Real Codebase Usage

In real projects, developers usually combine data-* attributes with event delegation and small handler functions.

Common pattern: delegated click handling

$("#list").on("click", "li", function () {
  const projectId = $(this).data("id");
  if (!projectId) return;

  DetailsView.GetProject(projectId, OnComplete, OnTimeOut, OnError);
});

This uses a guard clause:

if (!projectId) return;

That avoids making a bad request if the attribute is missing.

Common pattern: click on child, read from parent

Sometimes the click happens on an inner link or image, but the ID is stored on the parent:

$("#list").on("click", "a.project", function (event) {
  event.preventDefault();
  const projectId = $(this).closest("li").data("id");
  if (!projectId) return;

  DetailsView.GetProject(projectId, OnComplete, OnTimeOut, OnError);
});

Validation before sending to a service

$("#list").on("click", "li", function () {
  const projectId = $(this).data("id");

  if (typeof projectId !== "string" || projectId.trim() === "") {
    console.error("Missing or invalid project ID");
    return;
  }

  DetailsView.GetProject(projectId, OnComplete, OnTimeOut, OnError);
});

These patterns make code more reliable when markup changes or data is incomplete.

Common Mistakes

1. Using #data-id instead of data-id

Broken code:

$(this).attr("#data-id")

Why it is wrong:

  • #data-id looks like a CSS selector.
  • .attr() expects just the attribute name.

Correct code:

$(this).attr("data-id")

or:

$(this).data("id")

2. Binding directly to elements that get replaced

Broken approach:

$("#list li").on("click", function () {
  alert($(this).data("id"));
});

This works only for the li elements that exist when the code runs. If Quicksand replaces or reorders elements, the handler may stop working.

Better approach:

$("#list").on("click", "li", function () {
  alert($(this).data("id"));
});

3. Reading from the wrong element

If the user clicks the inner a or img, the ID may be on the parent li, not the clicked child.

Example:

$("#list").on("click", "a.project", function () {
  alert($(this).data("id")); // undefined if data-id is on li
});

Correct:

$("#list").on("click", "a.project", function () {
  alert($(this).closest("li").data("id"));
});

4. Forgetting to stop link navigation

If you click an <a href="#">, the page may jump.

$("#list").on("click", "a.project", function (event) {
  event.preventDefault();
  const projectId = $(this).closest("li").data("id");
  alert(projectId);
});

5. Assuming the value always exists

Always check before using it in a request.

const projectId = $(this).data("id");
if (!projectId) {
  console.error("No data-id found");
  return;
}

Comparisons

ApproachExampleBest useNotes
.attr('data-id')$(this).attr('data-id')Read the raw attribute valueGood when you want the exact attribute string
.data('id')$(this).data('id')Work with data-* values in jQueryCleaner and more semantic for custom data
Direct binding$('#list li').on('click', fn)Static elements already on the pageMay fail if elements are replaced dynamically
Delegated binding$('#list').on('click', 'li', fn)Dynamic or re-rendered elementsPreferred for sorted, filtered, or injected items

.attr() vs .data()

  • Use .attr('data-id') when you want the literal HTML attribute value.
  • Use .data('id') when you are working with custom data in a jQuery-friendly way.

Direct binding vs delegated binding

  • Direct binding attaches the event to each matched element now.
  • Delegated binding attaches one event to a stable parent and works for current and future matching children.

For Quicksand-style DOM updates, delegated binding is usually the safer choice.

Take Quiz

Cheat Sheet

Reading data-* in jQuery

$(element).attr('data-id')
$(element).data('id')

Correct examples

$(this).attr('data-id')
$(this).data('id')

Incorrect example

$(this).attr('#data-id')

Event binding

Static elements

$('#list li').on('click', function () {
  console.log($(this).data('id'));
});

Dynamic elements

$('#list').on('click', 'li', function () {
  console.log($(this).data('id'));
});

If the click is on a child element

$('#list').on('click', 'a.project', function (event) {
  event.preventDefault();
  console.log($(this).closest('li').data('id'));
});

Rules to remember

  • Use data-id, not #data-id
  • # is for selectors, not attribute names
  • Use event delegation for dynamic DOM updates
  • Use .closest() when the data is stored on a parent element
  • Validate the value before sending it to a service

FAQ

How do I get a data-id attribute in jQuery?

Use either:

$(this).attr('data-id')

or:

$(this).data('id')

Why does $(this).attr('#data-id') return undefined?

Because #data-id is not an attribute name. The # symbol is used in CSS selectors for IDs. The correct attribute name is data-id.

Should I use .attr() or .data() in jQuery?

For data-* attributes, .data() is usually more readable. .attr() is also valid when you want the raw attribute value.

How do I handle clicks on elements added after page load?

Use delegated events:

$('#list').on('click', 'li', function () {
  console.log($(this).data('id'));
});

What if the data-id is on the parent li, but I click the link inside it?

Use .closest() to move up to the parent:

$(this).closest('li').data('id')

Can I store more than one custom value with data-* attributes?

Yes. For example:

<li data-id="40" data-status="active" data-category="design"></li>

Then read them with jQuery:

$(this).data('id')
$(this).data('status')
$(this).data('category')
Take Quiz

Mini Project

Description

Build a small project list where each item has a data-id. When a user clicks a project link, your script should read the ID and display which project would be loaded. This demonstrates reading data-* attributes, delegated click handling, and accessing data stored on parent elements.

Goal

Create a clickable project list that reads data-id values correctly and uses them in JavaScript logic.

Requirements

  1. Create a list with at least three li items, each containing a unique data-id.
  2. Put a clickable link inside each list item.
  3. Use delegated event binding with .on() on the parent list.
  4. Prevent the default link behavior.
  5. Read the data-id from the clicked item's parent li and show it on the page.
Take Quiz

Keep learning

Related questions

View more