completefrontend
Open lab My progress
THE JAVASCRIPT FIELD GUIDE

Attributes & properties

Learn the difference between HTML attributes and DOM properties: getAttribute, setAttribute, reflection, dataset, input defaults, and boolean attributes.

By the end, you can
  • 01
    Read the right sideChoose the attribute for the starting value and the property for the value now.
  • 02
    Predict how they linkSay what id, className, href, style, value, and checked give on each side.
  • 03
    Use your own data safelyKeep small text in data-* attributes, and turn boolean attributes on and off correctly.

Two places for information

An element is one piece of a web page, such as a button or a text box. Each element can keep information in two places:

  • An attribute is a name and a value written in the HTML, such as id="save" or value="Ada". Its value is always text.
  • A property is a field on the element's object in JavaScript, such as button.id or input.value. The browser makes one object for each element. All these objects together are called the DOM.

Why two places? A page changes while people use it. A user types in a box. A user ticks a checkbox. Your code changes a value.

  • Attributes usually keep the starting setup, as text.
  • Properties usually keep how things are right now. A property can also be another type: true or false, a number, or an object.
One input with two different valuesPop out in the code editor (opens in a new tab)JavaScript
const input = document.createElement("input");
input.setAttribute("value", "Ada");
input.value = "Grace";
console.log(input.getAttribute("value"));
console.log(input.value);

Line 1 makes a new text box, an input element. Line 2 sets its value attribute to Ada. Line 3 sets its value property to Grace, just as typing would. Line 4 reads the attribute and prints Ada. Line 5 reads the property and prints Grace. The rest of this lesson keeps coming back to this split.

Left: getAttribute("value") reads the attribute, a tag that says "Ada", the starting value. Right: input.value reads the property, a value card inside the input object that says "Grace", what is in the box now.getAttribute("value")attribute"Ada"the starting valueinput.valuevalue: "Grace"inputwhat is there now
One input, two places. The attribute still says "Ada", the value from line 2. The property says "Grace", what is in the box right now.
Real-life analogyThe label on the box and the toy inside

A toy box has the label “red car.” A child paints the car blue. The car is now blue, but the box still says red. For a text box, the value attribute is the label on the box. The value property is what is in the text box right now.

In real life: The label printed on the box
In JavaScript: The attribute you wrote, like value="Ada"
In real life: The toy as it is now, after you paint it
In JavaScript: The property, like input.value after typing
In real life: Reading the box label again later
In JavaScript: defaultValue or defaultChecked, which give the starting value
In real life: Painting the toy
In JavaScript: Setting a property, like input.value = "Grace"

Before this lesson, you should know The browser environment, The DOM tree, Walking & searching the DOM, and Node properties & contents. The next lesson, Creating & changing elements, uses these reads and writes to build new elements.

getAttribute and setAttribute

INTERACTIVE

Four methods work with attributes:

  • element.getAttribute(name) reads an attribute. It gives back text, or null if the attribute is not there. null means "no value".
  • element.setAttribute(name, value) writes an attribute. It turns the value into text first.
  • element.hasAttribute(name) gives true if the attribute is there, and false if it is not.
  • element.removeAttribute(name) deletes an attribute.

Upper and lower case don't matter in attribute names on HTML elements. getAttribute("ID") and getAttribute("id") read the same attribute.

The four attribute methodsPop out in the code editor (opens in a new tab)JavaScript
const card = document.createElement("article");
card.setAttribute("data-count", 3);
console.log(card.getAttribute("data-count"));
console.log(card.hasAttribute("data-count"));
card.removeAttribute("data-count");
console.log(card.getAttribute("data-count"));
card.setAttribute("color", "teal");
console.log(card.getAttribute("color"));
console.log(card.color === undefined);

Line 2 writes the number 3. The attribute stores it as the text "3", so line 3 prints 3. Line 4 prints true because the attribute is there. Line 5 removes it. Line 6 prints null because the attribute is now gone.

Lines 7 to 9 use a made-up attribute, color. HTML has no color attribute for this element. Line 8 still reads it and prints teal. But the browser makes no property for it, so card.color is undefined and line 9 prints true.

Use hasAttribute when you only need to know if an attribute is there. Use getAttribute when you need its text.

Fun fact: attributes are objects too

element.attributes holds every attribute of an element. It is a NamedNodeMap: a list you can look up by name. Each item in it is an Attr object with a name and a value. Most code uses the four methods above instead.

Try the inspector below. It has a real text box and a real checkbox. Type something in the text box first. Then press setAttribute value: only the attribute and the starting value change. Then press write input.value: the text in the box changes.

Attribute vs property inspector
What the inspector reads and writesPop out in the code editor (opens in a new tab)JavaScript
const input = document.querySelector("input"); input.value;                 // property: current typed textinput.getAttribute("value"); // attribute: default from HTMLinput.defaultValue;          // property reflecting that default input.setAttribute("value", "Linus");input.value = "Grace";
Real text box and checkboxlive
input.value
""
input.getAttribute("value")
null
input.defaultValue
""
checkbox.checked
false
checkbox.getAttribute("checked")
null
checkbox.defaultChecked
false
Try it yourself

Type in the text box or tick the checkbox. Then compare the properties (the values now) with the attributes (the starting values).

The buttons change a real text box and a real checkbox. Each card on the right shows one attribute or property.

How attributes and properties stay linked

TABLE

Many built-in attributes are linked to a property. When you change one, the browser updates the other. This link is called reflection: we say the property reflects the attribute.

But the two sides don't always have the same name or the same type. Check the rule for each one you use. In the table below, each row is one attribute. Read across to see what each side gives you.

What the attribute and the property give for common attributes
AttributeReading the attribute givesReading the property givesWhat to remember
idThe text you wrote.el.id gives the same text.The two sides stay the same both ways.
classThe class text, like "quiet".el.className gives the same text. el.classList helps add or remove one class.The name changes because class already means something in JavaScript.
hrefThe text as written, like /docs.a.href gives the full web address.Use the attribute for the written text. Use the property for where the link really goes.
valueThe starting value.input.value gives the text in the box now.input.defaultValue is the property for the starting value.
checkedWhether the box started ticked. The attribute is there if it did.checkbox.checked gives true or false for now.checkbox.defaultChecked is the property for the starting state.
styleThe CSS as one piece of text.el.style gives a CSSStyleDeclaration object, with one field per CSS setting.el.style.color = ... changes one CSS setting.
for on <label>The for text.label.htmlFor gives the same text.The name changes because for already means something in JavaScript.
tabindexText, or null if it is not there.el.tabIndex gives a number.Some properties are numbers, not text.
color on <div>Your made-up text.Usually undefined.Made-up attributes get no property.

The next code block tries three of these rules. It first adds a <base> element to the page. A <base> element sets the page's base address: the address that short links like /docs are joined to.

Reading href, className, and stylePop out in the code editor (opens in a new tab)JavaScript
const base = document.createElement("base");
base.href = "https://example.test/app/";
document.head.append(base);
const link = document.createElement("a");
link.setAttribute("href", "/docs");
link.className = "quiet";
link.style.color = "teal";
console.log(link.getAttribute("href"));
console.log(link.href);
console.log(link.className);
  • Line 8 reads the href attribute and prints /docs, just as written.
  • Line 9 reads the href property and prints https://example.test/docs. The browser joined /docs to the base address.
  • Line 10 prints quiet. className is the property for the class attribute, set on line 6.
  • Line 7 uses style as an object: link.style.color changes just the color.
Left: getAttribute("href") gives /docs, the text as written. An arrow labelled adds the base leads right to link.href, which gives https://example.test/docs, the full address.getAttribute("href")/docsas writtenadds the baselink.hrefhttps://example.test/docsthe full address
The attribute keeps the text as written, /docs. The property gives the full web address: the browser joins /docs to the page's base address.

The step-through in the next section can't use a real page. So it uses a small plain object that copies how a text box behaves. Here is its full code. A real text box gives the same results.

A plain object that acts like a text boxPop out in the code editor (opens in a new tab)JavaScript
function makeInput(defaultValue) {  return {    attributes: { value: String(defaultValue) },    value: String(defaultValue),    defaultValue: String(defaultValue),    getAttribute(name) {      return Object.hasOwn(this.attributes, name) ? this.attributes[name] : null;    },    setAttribute(name, value) {      this.attributes[name] = String(value);      if (name === "value") this.defaultValue = String(value);    },    removeAttribute(name) {      delete this.attributes[name];      if (name === "value") this.defaultValue = "";    },  };} const input = makeInput("Ada");input.value = "Grace";input.setAttribute("value", "Linus");console.log(input.value);console.log(input.getAttribute("value"));console.log(input.defaultValue);

Lines 1 to 18 build the stand-in text box. Lines 20 to 25 use it. Line 21 acts like typing. Line 22 changes the attribute.

Text boxes, checkboxes, and starting values

STEP THROUGH

Text boxes and checkboxes are where people get mixed up most. A text box is an input element. It has three values to know:

  • input.value is the text in the box now.
  • input.getAttribute("value") is the starting text, from the attribute.
  • input.defaultValue is a property that also gives the starting text.

A checkbox works the same way:

  • checkbox.checked is true if the box is ticked now.
  • The checked attribute says whether the box started ticked.
  • checkbox.defaultChecked is a property that also gives the starting state.
A checkbox has a state now and a starting statePop out in the code editor (opens in a new tab)JavaScript
const checkbox = document.createElement("input");
checkbox.type = "checkbox";
checkbox.setAttribute("checked", "");
checkbox.checked = false;
console.log(checkbox.checked);
console.log(checkbox.defaultChecked);
console.log(checkbox.hasAttribute("checked"));

Line 2 makes the input a checkbox. Line 3 adds the checked attribute, so the box starts ticked. Line 4 unticks it by setting only the property. Line 5 prints false: the box is not ticked now. Lines 6 and 7 print true and true: defaultChecked and the attribute still say it started ticked.

Now step through the stand-in text box from the last section. Watch the attribute and the property split apart at line 21.

Step through attributes vs properties
Step 0 of 6Ready
Your turn: follow the blue line

This plain object copies how a real text box keeps its value now apart from its starting value. A real text box prints the same three lines.

Running in
  1. script
Next: line 20
function makeInput(defaultValue) {  return {    attributes: { value: String(defaultValue) },    value: String(defaultValue),    defaultValue: String(defaultValue),    getAttribute(name) {      return Object.hasOwn(this.attributes, name) ? this.attributes[name] : null;    },    setAttribute(name, value) {      this.attributes[name] = String(value);      if (name === "value") this.defaultValue = String(value);    },    removeAttribute(name) {      delete this.attributes[name];      if (name === "value") this.defaultValue = "";    },  };} input.value = "Grace";input.setAttribute("value", "Linus");console.log(input.value);console.log(input.getAttribute("value"));console.log(input.defaultValue);
CallStoreChangeResultBlue line: runs next. Ran: already executed.
Recent returnsNothing yet. Start with the blue line.
A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.
Attribute or property?
  • The text typed in a text box right now
  • The value written in the HTML at the start
  • The full web address a link goes to
  • The exact href="/docs" text as written
  • data-user-id read as userId
  • Whether a checkbox is ticked after a click
  • Whether the checkbox started ticked in the HTML
  • dataset.lastSeen = 7 creating data-last-seen
  • Can the button be clicked right now?
Try it yourself
0 of 9 correct

Sort each item by where you would read it: the attribute (the starting value), the property (the value now), or dataset (your own data-* notes).

Choose a category for every card. You can change an answer at any time; Reset clears them all.

data-* and dataset

INTERACTIVE

Sometimes your own code needs to keep a small piece of text on an element, such as a user's ID. Use an attribute whose name starts with data-, like data-user-id. These are called data-* attributes. HTML never uses these names for anything else, so they are safe to use.

JavaScript reads them through element.dataset. The name changes from HTML style to JavaScript style, which is called camelCase:

  • Drop data- from the front.
  • A dash followed by a small letter becomes that letter as a capital.
  • So data-user-id becomes dataset.userId.

It works the other way too. Setting dataset.someValue creates the attribute data-some-value.

dataset changes the name and stores textPop out in the code editor (opens in a new tab)JavaScript
const item = document.createElement("li");
item.dataset.userId = 42;
console.log(item.getAttribute("data-user-id"));
console.log(typeof item.dataset.userId);
console.log(Number(item.dataset.userId));

Line 2 sets dataset.userId to the number 42. Line 3 reads the attribute data-user-id and prints 42. Line 4 prints string: the number was stored as text. Line 5 uses Number(...) to turn the text back into a number and prints 42. Only do that when you need to do maths with it.

dataset.userId = 42, the JavaScript name, has an arrow to data-user-id="42", the HTML name. The number 42 is stored as the text "42".dataset.userId = 42JavaScript namedata-user-id="42"HTML name
Line 2 writes userId through dataset. The browser stores it as the attribute data-user-id, and the number 42 becomes the text "42".

Anyone can see data-* attributes in the page. Never keep passwords or other secrets in them.

Real-life analogydata-* attributes are sticky notes

You stick a small note on the element. Later, your code reads the note. You don't have to make up your own attribute names like userId="42", which HTML doesn't know.

In real life: A sticky note: customer #42
In JavaScript: data-user-id="42"
In real life: Reading the note later
In JavaScript: element.dataset.userId
In real life: Adding a new note
In JavaScript: element.dataset.lastSeen = "today"
Try dataset
How data-* names changePop out in the code editor (opens in a new tab)JavaScript
const card = document.querySelector("[data-user-id]"); card.dataset.userId;       // "42"card.dataset.role;         // "admin"card.dataset.lastSeen = 7; // creates data-last-seen="7"delete card.dataset.role;  // removes data-role
The card's attributestext
dataset.userId
undefined
dataset.role
undefined
dataset.lastSeen
undefined
data-* attributes
{}
Try it yourself

Read the sticky notes: data-user-id becomes dataset.userId, and data-role becomes dataset.role.

Use dataset for small pieces of text your own code keeps on an element. Anyone can see them, so keep no secrets there.

Boolean attributes

INTERACTIVE

Some attributes work like on/off switches. They are called boolean attributes, because true and false are called booleans. Examples are disabled, checked, hidden, and required.

For these, only one thing matters: is the attribute there? If it is there, the feature is on. Its text does not matter. Even "false" or "0" leave it on. To turn it off, do one of these:

  • Remove the attribute with removeAttribute.
  • Set the property to false, like button.disabled = false.
Left: a button with a disabled tag that says "false" attached. button.disabled is still true. Right: after removeAttribute("disabled") the button has no tag, and button.disabled is false.disabled="false"buttondisabled"false"button.disabled: trueremoveAttribute("disabled")buttonbutton.disabled: false
The browser only checks whether the disabled attribute is there. It never reads the text "false". Removing the attribute is what turns it off.

toggleAttribute(name, on) adds or removes an attribute in one step. If the second value is true, it adds the attribute. If it is false, it removes it.

toggleAttribute adds or removes an attributePop out in the code editor (opens in a new tab)JavaScript
const button = document.createElement("button");
button.toggleAttribute("disabled", true);
console.log(button.hasAttribute("disabled"));
button.toggleAttribute("disabled", false);
console.log(button.disabled);

Line 2 adds disabled, so line 3 prints true. Line 4 removes it, so line 5 prints false from the disabled property. The second value is handy when you already have a true or false in a variable, such as isSaving.

Real-life analogyA “Closed” sign on a shop door

When a shop has a “Closed” sign on its door, people see the sign and walk away. Nobody reads the small writing on it. To open the shop, you take the sign down.

In real life: A “Closed” sign hanging on the door
In JavaScript: A boolean attribute on the element, like disabled
In real life: Someone writes “false” on the sign
In JavaScript: disabled="false": the button is still disabled
In real life: Taking the sign down
In JavaScript: removeAttribute("disabled")
Try boolean attributes
Turning disabled on and offPop out in the code editor (opens in a new tab)JavaScript
const button = document.querySelector("button"); button.setAttribute("disabled", "false");button.hasAttribute("disabled"); // truebutton.disabled;                 // truebutton.removeAttribute("disabled");button.disabled = false;button.toggleAttribute("disabled", true);
Button stateenabled
hasAttribute("disabled")
false
getAttribute("disabled")
null
button.disabled
false
Try it yourself

A boolean attribute is on whenever it is there.

Only one thing matters: is the attribute there? The text inside it is never read as true or false.

Where you will use this

Real code often uses both sides. Use attributes for:

  • Starting values and settings written in the HTML.
  • ARIA attributes. These describe the page for screen readers and other tools that help people use it.
  • Anything a CSS selector should match, like [data-panel].

Use properties for how things are right now, and for values the browser works out, like a full link address. Here is a tab button that shows a panel. It uses both sides:

A tab that uses attributes and propertiesPop out in the code editor (opens in a new tab)JavaScript
const tab = document.querySelector("[data-panel]");const panelId = tab.dataset.panel;const panel = document.getElementById(panelId); tab.setAttribute("aria-selected", "true");tab.disabled = true;panel.hidden = false;
  • Line 2: tab.dataset.panel reads the sticky note. It holds the ID of the panel to show.
  • Line 5: setAttribute("aria-selected", "true") writes an ARIA attribute. A screen reader can then say that the tab is selected.
  • Line 6: tab.disabled = true sets the property. The browser also adds the disabled attribute.
  • Line 7: panel.hidden = false sets the property, so the panel shows now.

Common misconceptions

  • “Attributes and properties are the same thing.” Many are linked. But attributes are text from the HTML, usually the starting values. Properties are fields on the live object, usually the values now.
  • “setAttribute("value", ...) always changes the text in the box.” Once the user has typed, it only changes the starting value. Set the value property to change the text in the box.
  • “disabled="false" means not disabled.” A boolean attribute is on whenever it is there. Its text is ignored.
  • “dataset can store numbers and objects.” dataset values are always text. Turn them back with Number(...), or with JSON.parse(...) if you stored JSON text.
  • “Every attribute has a property with the same name.” Some properties have a new name, like className. Some have another type, like tabIndex, which is a number. Made-up attributes have no property at all.
  • “getAttribute gives undefined when the attribute is missing.” It gives null.

Practice exercises

5 EXERCISES
Exercise 1 · Warm-upMissing attribute

A new paragraph has no title attribute. What does this line give back?

Starter codePop out in the code editor (opens in a new tab)JavaScript
document.createElement("p").getAttribute("title");

Answer, then press Check. Spacing and letter case don’t matter.

    Exercise 2 · Warm-upDataset values are text

    This program acts like dataset: it turns the value into text before storing it. What type does the first line print?

    Starter codePop out in the code editor (opens in a new tab)JavaScript
    const dataset = {};
    dataset.count = String(5);
    console.log(typeof dataset.count);
    console.log(dataset.count);

    Answer, then press Check. Spacing and letter case don’t matter.

      Exercise 3 · PracticeFind the boolean bug

      The developer wanted a button that works. What does this code print, and what is the bug?

      Starter codePop out in the code editor (opens in a new tab)JavaScript
      button.setAttribute("disabled", "false");
      console.log(button.disabled);

      Answer, then press Check. Spacing and letter case don’t matter.

        Exercise 4 · PracticePredict the step-through

        Think back to the step-through. What three lines does this program print?

        Starter codePop out in the code editor (opens in a new tab)JavaScript
        function makeInput(defaultValue) {
          return {
            attributes: { value: String(defaultValue) },
            value: String(defaultValue),
            defaultValue: String(defaultValue),
            getAttribute(name) {
              return Object.hasOwn(this.attributes, name) ? this.attributes[name] : null;
            },
            setAttribute(name, value) {
              this.attributes[name] = String(value);
              if (name === "value") this.defaultValue = String(value);
            },
            removeAttribute(name) {
              delete this.attributes[name];
              if (name === "value") this.defaultValue = "";
            },
          };
        }
        
        const input = makeInput("Ada");
        input.value = "Grace";
        input.setAttribute("value", "Linus");
        console.log(input.value);
        console.log(input.getAttribute("value"));
        console.log(input.defaultValue);

        Answer, then press Check. Spacing and letter case don’t matter.

          Exercise 5 · ChallengeChoose the right tool

          Replace each comment with the code that fits the job best.

          Starter codePop out in the code editor (opens in a new tab)JavaScript
          const item = document.querySelector("[data-price]");
          // 1. Read the price note.
          // 2. Disable the buy button.
          // 3. Store a selected default in markup.

            Quiz

            7 QUESTIONS
            Attributes & properties quiz · 7 questionsScore: first tries count
            1. Question 1 of 7Which sentence best describes an HTML attribute?

              Choose an answer to see the explanation.

            2. Question 2 of 7This code acts like reading back setAttribute("size", 7), then reading a missing attribute. What does it print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              console.log(String(7));
              console.log(null);

              Choose an answer to see the explanation.

            3. Question 3 of 7For <a href="/docs">, which read gives the full web address?

              Choose an answer to see the explanation.

            4. Question 4 of 7This program acts like dataset. What does it print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              const dataset = {};
              dataset.count = String(5);
              console.log(typeof dataset.count);
              console.log(dataset.count);

              Choose an answer to see the explanation.

            5. Question 5 of 7What does disabled="false" do in HTML?

              Choose an answer to see the explanation.

            6. Question 6 of 7Which property is linked to the for attribute on a <label>?

              Choose an answer to see the explanation.

            7. Question 7 of 7A user has typed in a text box. What does setAttribute("value", "new") change now?

              Choose an answer to see the explanation.

            Key takeaways

            • Attributes are text written in the HTML, usually the starting values. Properties are fields on the element's live object, usually the values now.
            • getAttribute gives text or null. setAttribute turns any value into text.
            • Linked pairs don't always match. A property can have a new name (className), another type (tabIndex), or a worked-out value (the full href).
            • For text boxes and checkboxes, value and checked are the state now. The attributes, defaultValue, and defaultChecked are the starting state.
            • data-* attributes show up in dataset with camelCase names, always as text.
            • Boolean attributes are on when they are there. Remove them, or set the property to false, to turn them off.
            Final definition

            An attribute is text on an element, written in the HTML, that usually holds a starting value. A property is a field on the element's live JavaScript object that usually holds the value now.

            Up next: Creating & changing elements.

            CompleteFrontend Clear concepts. Working examples.