3

I'm confused by the difference between "HTML attribute" and "property of the DOM element". From this post, I learned that getAttribute("class") returns the former, while element.className returns the latter. However, I could't understand the output of the following code:

var span = document.querySelector("#span");
console.log(span.className + ' ' + span.getAttribute("class"));
span.className = "bar";
console.log(span.className + ' ' + span.getAttribute("class"));
<span id="span" class="foo"><span>

I expect the result to be

foo foo
bar foo

because in my understanding the content of my HTML file hasn't been changed while javascript is run. Furthermore, when I replace the span.className = "bar"; line with span.setAttribute('class', 'bar');, same result remains.

My question is: What's the difference and relationship between "HTML attribute" and "property of the DOM element"?

Community
  • 1
  • 1
nalzok
  • 14,965
  • 21
  • 72
  • 139
  • 3
    An HTML attribute is what you write in the markup. The attributes become part of the DOM just like everything else. Some of those attributes get mapped directly to properties directly on the DOM element when created. Of those, a subset of them maintains a live mapping between the attribute and property, so both are updated when one is changed. The `class` attribute is one of those. –  Sep 04 '16 at 23:54
  • 1
    @squint I think this can be a nice answer. – nalzok Sep 04 '16 at 23:56
  • I'll let you or someone else dig a little deeper into the intricacies of it all and post an answer. My work here is done... –  Sep 04 '16 at 23:57
  • Just on the `className` bit, that particular name is due to a quirk in the JavaScript language. At the time, JavaScript keywords could not be used for property names, so `element.class` would be an error. `class` was a reserved word even though it wasn’t being used at the time. The irony is by the time `class` became part of the language, the restriction was removed, and it’s safe to use keywords for property names. So in this case, `class` was never going to be a problem. – Manngo Apr 24 '19 at 21:35

2 Answers2

3

To confuse matters further, the HTML5 spec refers to them as content attributes, and IDL attributes respectively.

They are sometimes associated by the same names, and sometimes not.

In the most common type of association, the two types of attribute are said to "reflect" each other, so that when one changes so does the other. HTML5 describes this in Reflecting content attributes in IDL attributes. The first paragraph says:

Some IDL attributes are defined to reflect a particular content attribute. This means that on getting, the IDL attribute returns the current value of the content attribute, and on setting, the IDL attribute changes the value of the content attribute to the given value.

Sometimes the IDL attribute and the content attribute which reflect one another have different names. For example, the input "value" content attribute is reflected by the defaultValue IDL attribute.

Sometimes the association between the two is more complex; changes to one may affect the other but not be a direct one-to-one mapping.

Alohci
  • 78,296
  • 16
  • 112
  • 156
3

In most cases, modification to attributes will be represented in properties too, and vice versa. Just like in your sample code.

However, some attributes/properties in form elements are different. Initially the property values are retrieved from relevant attributes, but then they don't affect each other any more.

Please note the markup before and after each modification:

var el = document.querySelector('input')
console.log(el.value + ' ' + el.getAttribute('value'))
console.log(el.outerHTML)
el.value = 'prop'
console.log(el.value + ' ' + el.getAttribute('value'))
console.log(el.outerHTML)
el.setAttribute('value', 'attr')
console.log(el.value + ' ' + el.getAttribute('value'))
console.log(el.outerHTML)
<input type="text" value="123">
Leo
  • 13,428
  • 5
  • 43
  • 61