DOM Attribute Nodes
4 min read
We are used to mutating element attributes as strings using the getAttribute
and setAttribute
methods.
tabs.setAttribute("role", "tablist");
tabs.getAttribute("role"); // tablist
Attr nodes
Read section Attr nodesThe DOM Standard also specifies so-called Attr
nodes. The standard is not actually strictly tied to JavaScript. PHP, for example, also defines getAttributeNode in its DOM extension.
These nodes can be created through the document.createAttribute
method, and are also implicitly created whenever setAttribute
is used. setAttributeNode
, getAttributeNode
, and removeAttributeNode
are methods available on all elements which may be used to interact with attribute nodes.
<button id="coloredBtn" class="text-red-500">Background color added by JS</button>
<script>
const coloredClass = coloredBtn.getAttributeNode("class");
coloredClass.value = "bg-black text-white border-white";
</script>
Newly set attributes can also be mutated via their implicitly-created node:
<button id="boldBtn">Bolded by JS</button>
<script>
boldBtn.setAttribute("class", "text-red-600");
const boldClass = boldBtn.getAttributeNode("class");
boldClass.value += " font-bold";
</script>
Even though Attr
nodes inherit from the Node
interface, they don’t have any interesting fields. Its ownerElement
field points to the DOM element it is attached to. name
, localName
, and nodeName
all refer to the attribute’s name. value
is used for reading and writing its value.
The spec describes the situation as such:
If designed today they would just have a name and value. ☹
.attributes
Read section .attributesAttribute nodes can also be referenced and assigned using the attributes
NamedNodeMap, with the getNamedItem
, setNamedItem
, and removeNamedItem
methods. These methods are equivalent to xAttributeNode
.
const disabled = document.createAttribute("disabled");
btn.attributes.setNamedItem(disabled);
btn.attributes.removeNamedItem(disabled);
Named attributes can also be retrieved as properties of attributes
.
const disabled = document.createAttribute("disabled");
btn.attributes.setNamedItem(disabled);
btn.attributes.disabled.value = false;
Setting new properties on attributes
does result in it being set on the object, however, the attribute is not reflected in the DOM.
btn.attributes.disabled = true;
btn.getAttribute("disabled"); // null
Practical use case
Read section Practical use caseThe most obvious use case would be to keep the same attribute on multiple nodes in sync.
const role = document.createAttribute("role");
role.value = "tab";
div1.setAttributeNode(role);
div2.setAttributeNode(role);
// This however fails, with the following error
// Uncaught DOMException: Attribute already in use
An error is thrown because a node can only have a single ownerElement
. It’s a shame, as keeping attribute values in sync is especially useful when building accessible applications. Tabs, for example, should update tabindex and aria-selected attributes in accordance with what tab is currently selected.
attr.cloneNode()
can be used to clone an attribute node, but these would obviously not be in sync.
Conclusion
Read section ConclusionAttribute nodes are not exactly a useful feature. It should be no surprise that this feature is on the long tail of little-used browser features, with almost no user ever hitting a page making use of it. The Chrome Platform Status feature rankings page, powered by anonymous usage statistics, claims this function is used on fewer than 0.000001% of page views.
Older versions of jQuery (before v1.10) actually made use of the getAttributeNode
function in one place, but it was removed due to Firefox firing warnings. The warnings have been retired since. Presumably, the only usage of this method occurs in pages using old versions of jQuery.