I'm puzzled by the reason behind how the relationship between some DOM element's property
and its corresponding attributes
works.
Below is a graph from the book jquery in action 2015 Bear Bibeault
, showing the relationship between property
and attribute
of DOM element.
To further explain the concept, the author had the following code and explanation for the code.
My question is, why some property
and attribute
are synced, why some are not synced, and why some attributes
does not have corresponding property
?
I have found a great post explaining the relationship between property
and attribute
, but it didn't touch on why it was designed this way. I hope to understand the reasons behind the design.
A related question, if I want to get or set a value on a DOM element, should I get/set the property
or the attribute
?
And how do we find the relationship between a particular property
and its corresponding attribute
when we need to? Is there a documentation specifically detailing the relationship?
An attribute is a quality or character ascribed to or considered to belong to, or be inherent in, a person or thing. A property is a quality or characteristic belonging to a person or thing, with its original use implying ownership, and also either being essential or special.
The attributes have a data type of string. So no matter the value of the attribute, it will always return a string. Property: In contrast to the attributes, which are defined in HTML, properties belong to the DOM. Since DOM is an object in JavaScript, we can get and set properties.
Once the browser parses this code, a HTMLInputElement object will be created, and this object will contain dozens of properties like: accept, accessKey, align, alt, attributes, autofocus, baseURI, checked, childElementCount, childNodes, children, classList, className, clientHeight, etc.
DOM is something that has grown "naturally" to a large degree. You have to consider, HTML (meaning: attributes) came first and originally there was no scripting whatsoever. Eventually, Netscape introduced JavaScript with what you would consider an extremely limited API today. This API was geared towards manipulating forms, not really arbitrary HTML elements. And then Netscape and Internet Explorer came out with different variants of what they called DHTML back then (Dynamic HTML). Netscape's variant relied on a special <layer>
tag and nobody remembers it today. The Internet Explorer variant allowed more generic access to HTML elements and in particular had a 1:1 mapping of attributes to properties.
While Internet Explorer won this war, its DHTML variant was designed when people were thinking of HTML attribute names as a fixed collection. With arbitrary attributes, it had too many issues. For example:
class
attribute could not be mapped to JavaScript originally because class
is a reserved keyword. While subsequent changes to the JavaScript standard allowed using reserved keywords as property names, Internet Explorer has to map class
attribute to the className
property. Setting className
attribute on an element or el["class"]
property on a JavaScript object resulted in hilarious inconsistencies.<FOO SOMEATTIRIBUTE>
and you tried to access el.someAttribute
or el.SOMEATTRIBUTE
from JavaScript? I no longer remember, but it wasn't pretty.toString
for example cannot possibly be mapped to a property because it would mask the toString()
method.No browser other than Internet Explorer ever implemented this 1:1 mapping of attributes to properties, and even Internet Explorer gave up on it as soon as it was feasible in terms of backwards compatibility (this took a very long time). Instead, attributes and properties are treated as separate namespaces now. Browsers will provide you with some properties as shortcuts for attribute access and manipulation, but they are really only there for your convenience. And there are some backwards compatibility cases muddying the waters: the value
property and value
attribute are not actually mapped to each other, the former reflecting the current state of the element whereas the latter reflects its initial state.
Edit: Just for reference, you are quoting the following statement:
If attribute exists as a built-in property but it's a Boolean, the value isn't synchronized.
This is wrong, the behavior has nothing to do with booleans vs. strings. As mentioned above, the value
property is similarly missing synchronization as the checked
property. On the other hand, the boolean hidden
property will be synced with the corresponding attribute properly. From what I can tell, you will find missing sync between property and attribute around the original form manipulation APIs that have been introduced by Netscape - this is simply backwards compatibility.
So maybe you shouldn't trust people who write books on jQuery with DOM questions. After all, these explicitly chose to quit touching the DOM directly and opted for an entirely different representation with its very own set of quirks.
You will find the answers buried inside HTML specs. I first want you to have a look at the attributes and properties of the input
element (heading "Content attributes" and "DOM interface") and the section about attribute reflection (first paragraph).
You will notice that all attributes have corresponding properties and manipulating a property will change the attribute it reflects. It is worth noting that:
(1) An attribute could be reflected by a property with a slightly different name. The classical example is the class
attribute which is reflected by className
property and for
attribute which is reflected by htmlFor
property.
(2) Likewise the checked
attribute is reflected by defaultChecked
property whereas the checked
property represents the internal state of the checkbox irrespective of the checked
attribute. This has always caused confusion among programmers (and book authors). The difference is explained at the end of this answer.
(3) Made-up attributes (such as the "book" attribute in your example) will not generate corresponding property and vice-versa. For this purpose the HTML specs describe a mechanism called data attributes and dataset
property.
A related question, if I want to get or set a value on a DOM element, should I get/set the
property
or theattribute
?
Depends. For example both of the following produce identical result and HTML:
document.getElementById("div-1").title = "Hello";
document.getElementById("div-1").setAttribute("title") = "Hello";
However, for form elements you should manipulate the state instead of attribute. Suppose you have this HTML markup:
<input type="checkbox" id="checkbox-1">
And you execute either of the following:
document.getElementById("checkbox-1").defaultChecked = true;
document.getElementById("checkbox-1").setAttribute("checked", "checked");
And here is the result:
<input type="checkbox" id="checkbox-1" checked="checked">
But whether the checkbox actually get checked depends on the dirtiness of the control (i.e. if its state was changed at some point). For form elements you would normally manipulate the properties that correspond to the internal state:
document.getElementById("checkbox-1").checked = true;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With