JavaScriptBeginner

JavaScript DOM Attributes: getAttribute, setAttribute and More

Learn to read, change, remove and check HTML attributes with getAttribute, setAttribute, removeAttribute and hasAttribute, plus data attributes and properties.

All JavaScript lessons

What you will learn

HTML elements are not only tags. They carry extra information called attributes: the href of a link, the src of an image, the disabled state of a button, and so on. In this lesson you will learn how to read, change, remove and check attributes with getAttribute, setAttribute, removeAttribute and hasAttribute. You will also learn the difference between an attribute and a property, how boolean attributes work, and how to store your own data in data-* attributes.

What is an attribute?

An attribute is a name="value" pair written inside the opening tag:

<a href="/about" target="_blank" title="Read more">About us</a>

Here href, target and title are attributes. Think of an element as a person and attributes as the details on their ID card: name, age, address. JavaScript can read the card, correct a detail, add a new one, or tear a detail off.

You have already learned attributes in HTML (see the HTML Attributes in Depth lesson). Now we control them from JavaScript.

The sample page

All examples use this page. It is also loaded in Practice in Editor.

<h1 id="title">Attributes Practice</h1>

<a id="link" href="/about" target="_blank">About us</a>

<p>
  <img id="logo" src="logo.png" alt="Company logo" width="120">
</p>

<form>
  <input id="email" type="email" placeholder="Your email" required>
  <input id="password" type="password" placeholder="Password">
  <button id="save" type="submit" disabled>Save</button>
</form>

<div id="product" data-id="42" data-price="499" data-in-stock="true">Wireless Mouse</div>

Start your code with these variables:

const link = document.getElementById("link");
const email = document.getElementById("email");
const save = document.getElementById("save");
const product = document.getElementById("product");

The four main methods

Method What it does Returns
getAttribute(name) Reads the value A string, or null if the attribute does not exist
setAttribute(name, value) Adds the attribute, or changes it if it exists Nothing (undefined)
removeAttribute(name) Deletes the attribute Nothing (undefined)
hasAttribute(name) Checks if the attribute exists true or false

getAttribute

console.log(link.getAttribute("href"));     // "/about"
console.log(link.getAttribute("target"));   // "_blank"
console.log(link.getAttribute("rel"));      // null (there is no rel attribute)

The result is always a string, or null. Even a number such as width="120" comes back as the text "120":

const logo = document.getElementById("logo");

console.log(logo.getAttribute("width"));          // "120" (a string)
console.log(typeof logo.getAttribute("width"));   // "string"
console.log(Number(logo.getAttribute("width")) + 30);   // 150

setAttribute

The first argument is the name, the second is the value. If the attribute already exists, its value is replaced. If not, it is created.

link.setAttribute("href", "https://mycodenest.in");   // change
link.setAttribute("title", "Visit MyCodeNest");       // add new
link.setAttribute("rel", "noopener noreferrer");      // add new

console.log(link.getAttribute("href"));   // "https://mycodenest.in"

Open the Elements panel in DevTools and watch the <a> tag change live.

removeAttribute

link.removeAttribute("target");

console.log(link.getAttribute("target"));   // null

Removing an attribute that does not exist is safe. Nothing happens and there is no error.

hasAttribute

console.log(link.hasAttribute("href"));       // true
console.log(link.hasAttribute("download"));   // false

Use it when you only care whether something is present, not what its value is.

More attribute helpers

Member What it does
toggleAttribute(name) Adds the attribute if missing, removes it if present. Returns true if it is now present
toggleAttribute(name, force) force = true always adds it, force = false always removes it
getAttributeNames() An array of all attribute names of the element
attributes A list of all attributes; each has a name and a value
console.log(link.getAttributeNames());   // ["id", "href", "title", "rel"]

for (const attr of product.attributes) {
  console.log(attr.name + " = " + attr.value);
}

Output:

id = product
data-id = 42
data-price = 499
data-in-stock = true

Boolean attributes: disabled, required, checked, hidden

Some attributes do not need a value. If they are present, they are ON. If they are absent, they are OFF.

<button id="save" disabled>Save</button>   <!-- disabled: ON  -->
<button id="save">Save</button>            <!-- disabled: OFF -->

So to turn them on and off, add and remove the attribute:

save.removeAttribute("disabled");        // enable the button
save.setAttribute("disabled", "");       // disable it again (the value text does not matter)

save.toggleAttribute("disabled");        // flip it
save.toggleAttribute("disabled", false); // make sure it is enabled

The most common beginner bug is this:

save.setAttribute("disabled", "false");   // The button is STILL disabled!

The attribute is present, so it is ON. The text "false" does not matter. Remove the attribute instead.

Common boolean attributes: disabled, required, checked, selected, readonly, hidden, autofocus, multiple.

Attribute vs property

This is the idea that confuses most beginners, so let us go slowly.

  • An attribute is what is written in the HTML (the starting value).
  • A property is what lives on the DOM object (the current value).

Many attributes have a matching property, and for simple cases they stay in sync:

console.log(link.id);           // "link"  (property)
console.log(link.title);        // "Visit MyCodeNest"
link.title = "New title";       // changes the attribute too
console.log(link.getAttribute("title"));   // "New title"

But for some attributes they are different:

email.value = "riya@example.com";   // like the user typing

console.log(email.getAttribute("value"));   // null  (HTML never had a value attribute)
console.log(email.value);                   // "riya@example.com" (current value)

The same happens with checkboxes. The checked attribute is only the starting state. The checked property changes when the user clicks.

// <input type="checkbox" id="agree" checked>
// After the user unchecks the box:
// agree.hasAttribute("checked")  -> true   (still in the HTML)
// agree.checked                  -> false  (current state)

Links show a third difference. The attribute is exactly what you wrote. The property is the full address:

console.log(link.getAttribute("href"));   // "/about"  (as written)
console.log(link.href);                   // the complete URL, like "https://mycodenest.in/about"
Use When
Property (el.value, el.checked, el.disabled, el.src) You want the current state of the element. This is the best choice for most standard things
Attribute (getAttribute) You want the exact text written in the HTML, or the attribute has no property (like data-* or aria-*, or a custom one)

Two names are different in properties because class and for are reserved words in JavaScript:

HTML attribute Property
class className (or better, classList, which is the next lesson)
for (on <label>) htmlFor
tabindex tabIndex
readonly readOnly

Custom data: data-* attributes

HTML lets you invent your own attributes if the name starts with data-. They are perfect for hiding small pieces of information inside an element, like a product id.

<div id="product" data-id="42" data-price="499" data-in-stock="true">Wireless Mouse</div>

You can use getAttribute("data-id"), but there is an easier way: the dataset property.

console.log(product.dataset.id);         // "42"
console.log(product.dataset.price);      // "499"
console.log(product.dataset.inStock);    // "true"

Rules for dataset:

  • The name after data- is used without the prefix.
  • A name with dashes becomes camelCase: data-in-stock becomes dataset.inStock.
  • Values are always strings. "true" is not the boolean true, and "499" is not a number.
  • Change, add and delete work like a normal object.
product.dataset.discount = "10";                     // adds data-discount="10"
console.log(product.getAttribute("data-discount"));  // "10"

console.log("price" in product.dataset);             // true (check if it exists)
delete product.dataset.id;                           // removes data-id

const price = Number(product.dataset.price);
const inStock = product.dataset.inStock === "true";
console.log(price + 100, inStock);                   // 599 true

Tip: data-* attributes also work in CSS: [data-in-stock="false"] { opacity: 0.4; }. And never put secret data (like passwords) in them, because everyone can see the HTML.

Real use cases

1. Show and hide a password

The type attribute decides if the text is dots or visible. One click flips it.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Show Password</title>
  <style>
    body { font-family: sans-serif; padding: 20px; }
    input { padding: 8px; font-size: 16px; }
    button { padding: 8px 12px; font-size: 16px; cursor: pointer; }
  </style>
</head>
<body>
  <label for="pw">Password</label><br>
  <input id="pw" type="password" placeholder="Enter password">
  <button id="toggle" type="button">Show</button>

  <script>
    const pw = document.getElementById("pw");
    const toggle = document.getElementById("toggle");

    toggle.addEventListener("click", function () {
      const isHidden = pw.getAttribute("type") === "password";

      pw.setAttribute("type", isHidden ? "text" : "password");
      toggle.textContent = isHidden ? "Hide" : "Show";
    });
  </script>
</body>
</html>

(addEventListener means “when the button is clicked, run this function”. You will learn it fully in the events lessons.)

2. Enable the submit button only when the form is ready

Real sites keep “Create account” disabled until the user agrees to the terms. Here the disabled attribute is added and removed as the checkbox changes.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Terms</title>
  <style>
    body { font-family: sans-serif; padding: 20px; }
    button { padding: 10px 16px; font-size: 16px; }
    button:disabled { opacity: 0.5; cursor: not-allowed; }
  </style>
</head>
<body>
  <label>
    <input type="checkbox" id="agree"> I agree to the terms and conditions
  </label>
  <p><button id="create" disabled>Create account</button></p>

  <script>
    const agree = document.getElementById("agree");
    const create = document.getElementById("create");

    agree.addEventListener("change", function () {
      create.toggleAttribute("disabled", !agree.checked);
    });
  </script>
</body>
</html>

toggleAttribute("disabled", !agree.checked) means: disabled is ON when the box is NOT checked. Notice that we read the property agree.checked (the current state) and write the attribute disabled.

Each thumbnail carries the big image name in a data-full attribute, and we also keep alt text updated for accessibility.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Gallery</title>
  <style>
    body { font-family: sans-serif; padding: 20px; }
    .thumb { padding: 8px 12px; margin-right: 6px; cursor: pointer; }
    #big { margin-top: 12px; padding: 40px; border: 2px dashed #999; font-size: 18px; }
  </style>
</head>
<body>
  <button class="thumb" data-full="red-shoe.jpg" data-alt="Red running shoe">Red</button>
  <button class="thumb" data-full="blue-shoe.jpg" data-alt="Blue running shoe">Blue</button>
  <button class="thumb" data-full="green-shoe.jpg" data-alt="Green running shoe">Green</button>

  <div id="big">Click a colour</div>

  <script>
    const big = document.getElementById("big");

    document.querySelectorAll(".thumb").forEach(function (thumb) {
      thumb.addEventListener("click", function () {
        const file = thumb.dataset.full;
        const alt = thumb.dataset.alt;

        // In a real page, big would be an <img> and you would write:
        // big.setAttribute("src", "images/" + file);
        // big.setAttribute("alt", alt);
        big.textContent = "Showing images/" + file + " (alt: " + alt + ")";
      });
    });
  </script>
</body>
</html>

The page has no hard-coded list inside the script. To add a fourth colour, you only add one more button in the HTML.

Links that open in a new tab should have rel="noopener noreferrer". This script finds every link that goes to another site and fixes it.

document.querySelectorAll("a[href^='http']").forEach(function (a) {
  if (a.hostname !== location.hostname) {
    a.setAttribute("target", "_blank");
    a.setAttribute("rel", "noopener noreferrer");
  }
});

5. Accessibility: keep ARIA in sync

When a button opens a menu, screen readers need to know the state. Update aria-expanded along with what the user sees.

const menuButton = document.getElementById("menu-btn");

menuButton.addEventListener("click", function () {
  const open = menuButton.getAttribute("aria-expanded") === "true";
  menuButton.setAttribute("aria-expanded", String(!open));
});

aria-* attributes have no property, and values must be the strings "true" or "false". That is why String(!open) is used.

Common mistakes

  • setAttribute("disabled", "false"). The button stays disabled. Use removeAttribute("disabled") or toggleAttribute("disabled", false).
  • Expecting a number or boolean back. getAttribute("width") and dataset.price are strings. Convert with Number(), or compare with === "true".
  • Forgetting that a missing attribute is null. link.getAttribute("rel").toLowerCase() crashes if there is no rel. Check with hasAttribute, or use ?..
  • Using getAttribute("value") to read what the user typed. It gives the starting value only. Use input.value.
  • Using getAttribute("checked") for a checkbox state. Use checkbox.checked.
  • Writing getAttribute("class") to add classes. It replaces the whole class string and is easy to break. Use classList (next lesson).
  • Typing dataset.data-id. That reads as dataset.data minus id. Use dataset.id, and dataset.inStock for data-in-stock.
  • Setting an attribute from untrusted user input. A link built from user text can start with javascript:. Check that URLs start with https:// before you use them.
  • Wrong capital letters. It is setAttribute, not setattribute or SetAttribute.

Practice

  1. Print the href and target of the link with getAttribute. Then print getAttribute("rel") and explain why you get null.
  2. Change the link to go to https://mycodenest.in and add a title. Check the result in the Elements panel.
  3. Remove target from the link and use hasAttribute to confirm it is gone.
  4. Enable the Save button by removing disabled. Then disable it again with setAttribute.
  5. Try save.setAttribute("disabled", "false") on an enabled button. Is it disabled or enabled? Why?
  6. Set email.value from JavaScript. Print email.getAttribute("value") and email.value. Explain the difference.
  7. Print the href of the link with getAttribute("href") and with link.href. What is different?
  8. Loop over product.attributes and print every name and value.
  9. Read data-price from the product, convert it to a number, and print the price with 10% discount.
  10. Challenge: build a “Show / Hide” toggle for the #password field using setAttribute("type", ...), and also update the button’s aria-label between "Show password" and "Hide password".

Recap

  • Attributes are the name="value" details inside a tag. JavaScript can manage them with four main methods.
  • getAttribute(name) reads (a string, or null), setAttribute(name, value) adds or changes, removeAttribute(name) deletes, and hasAttribute(name) checks.
  • toggleAttribute(name, force) is a handy shortcut for adding and removing in one call. getAttributeNames() and attributes list everything.
  • Boolean attributes (disabled, required, checked, hidden) are ON when present and OFF when absent, whatever the value text is.
  • An attribute is the starting value in the HTML. A property is the current value on the object. For live state, like value, checked and disabled, prefer the property.
  • class is className (or classList) and for is htmlFor as properties.
  • Use data-* attributes with dataset to attach your own information. Names become camelCase and values are always strings.
  • Always handle null for missing attributes, and convert strings to numbers or booleans when needed.
  • Next you will learn how to change what an element shows: textContent, innerText, innerHTML and style.