For many years we have relied on third-party JavaScript libraries such as jQuery to write JavaScript for the web. However, in recent years, the DOM API has evolved a lot, so adding dynamic functionality to web pages using native JavaScript is becoming easier for developers.
This article is a high-level overview of the DOM API built into every modern web browser. We’ll look into what the DOM API is, how it’s related to JavaScript, and how you can use it to write JavaScript for the web.
What Is the DOM?
DOM stands for Document Object Model, and it’s the data representation of a web document, such as an HTML page, an SVG graphic, or an XML file.
In very plain English, the DOM is a bunch of objects (Document Object Model) that make up a web page. Each object is the real-world implementation of an interface — the blueprint that describes what an object should look like. Thus, one interface can be implemented by multiple objects.
For example, each HTML <form>
element is represented by a HTMLFormElement
object in the DOM, which is an implementation of the HTMLFormElement
interface. This interface comes with pre-written properties (interface variables) and methods (interface functions) that you can use to add dynamic functionality to each form object (that appears as a <form>
tag in the HTML document). For example, you can use HTMLFormElement.reset()
method to reset a form to its initial state.
Essentially, that’s how the entire DOM works. The most basic interface is called Node
— every HTML element, text string, and the document itself is a node too. Other interfaces extend the Node
interface and inherit its properties and methods, but as each interface can have children, inheritance works at multiple levels. For example, HTMLFormElement
is a child interface of HTMLElement
, which is a child interface of Element
, which is a child interface of Node
.
The web browser arranges all of these nodes into a document tree (DOM tree) that represents the nodes and the relationships between them as a tree hierarchy.
What is the DOM API?
While there are many DOMs (each HTML, XML, and SVG document has a DOM), there’s just one DOM API, which is a W3C specification. The DOM API is written in JavaScript, and you can use it to manipulate the DOM of a web document using JavaScript.
API stands for “Application Programming Interface”, and it’s a collection of classes, interfaces, properties, methods, and other code structures that developers can use to access the functionality of an application. For example, you can use the Twitter API to access tweets, users, messages, ads, and other elements of the Twitter application programmatically. Similarly, you can use web APIs to use the built-in functionalities of a web browser (which is an application too).
The DOM API is one of the multiple web APIs built into web browsers. There are lower-level APIs such as the Web Workers API (for background operations) and higher-level ones such as the DOM.
Most web APIs, including the DOM API, are written in JavaScript. First, the W3C creates the specifications, then browser vendors implement them. Thus, “browser support” refers to whether a browser has implemented a specific functionality of the DOM API or not. If browser support is good, you can safely use an object (interface implementation), property, or method in production, while if it’s poor, it’s better to find an alternative (you can check browser support on the CanIUse website).
HTML tags and attributes and CSS styles all have their handles in the DOM API so that you can modify them dynamically. For example, the following HTML tag:
<a href='page.html' target='_blank'>Click this link</a>
is represented by four nodes (one parent and three children) in the DOM:
- (parent node) an
HTMLAnchorElement
object in the DOM (that’s the implementation of theHTMLAnchorElement
interface); this is an element node - (child node) an
HTMLAnchorElement.href
property defined by theHTMLAnchorElement
interface; this is an attribute node - (child node) a
HTMLAnchorElement.target
property; this is another attribute node - (child node) a text node (“Click this link”)
Now, let’s see how you can use the DOM API in practice.
An Example of Using the DOM API
Let’s imagine you want to change the text color of the link above dynamically from the default blue to magenta.
If you analyze the documentation of the HTMLAnchorElement
interface, you won’t find any properties or methods that you can use for this purpose.
But, as HTMLAnchorElement
is a child interface of HTMLElement
, it inherits its properties and methods too. This interface has an HTMLElement.style
property that lets you change the CSS belonging to an HTML element. If you read its description in the docs, you’ll see that it can use properties from the CSS Properties Reference, also defined by the DOM API.
In our example, we’ll need to use the color
property, so we’ll write the following code:
element.style.color = 'magenta';
However, if we run this code, it will return a ReferenceError
exception in the console because element
is not defined. Before we can manipulate a DOM element with JavaScript, we need to select it using the DOM API and pass it to a variable.
To select nodes in a document, we’ll need to go to the Document
interface. This interface has two methods we can use, Document.querySelector()
that finds the first instance of a selector and Document.querySelectorAll()
that finds all instances of a selector. Here, we’ll use querySelector()
, as we have just one anchor element on the page. So, the new code is:
// selects the first 'a' element on the page let element = document.querySelector('a'); // sets the 'color' property to 'magenta' element.style.color = 'magenta';
Now, this code will work properly and change the link color to magenta. There are a few things to note here:
- as
style.color
is a property, we can set its value by using the assignment operator (= sign) - as
document.querySelector()
is a method (indicated by the parentheses after it), we can define its value by adding a parameter('a')
within the parentheses - while we need to define the
element
variable, we don't have to define thedocument
variable as it's a global object similar towindow
(the belonging variable is built into the browser — note that the object is written with capital initial e.g.Document
, while the variable is written with all lowercase e.g.document
) - if we had more than one link on the page, we’d need to use the
querySelectorAll()
method instead ofquerySelector()
and place theelement.style.color
declaration within afor
loop to change the color of all links on the page:
<a href='page01.html' target='_blank'>Link 01</a> <a href='page02.html' target='_blank'>Link 02</a> <a href='page03.html' target='_blank'>Link 03</a>
// selects all 'a' elements on the page let elements = document.querySelectorAll('a'); // loops through the element object which is a NodeList for (let i = 0; i < elements.length; i++) { // sets the 'color' property to 'magenta' elements[i].style.color = 'magenta'; }
We need to loop through the elements
variable because querySelectorAll()
returns a NodeList
object that includes more than one item.
What Type of Object is Returned?
It’s always important to know what type of object a method returns, as it defines your options. For instance, as querySelector()
returns an Element
object that has just one element, we didn’t have to loop through it in the previous example.
You can either check the return type in the method’s documentation or by using the console.log()
method and run the code in the console of your browser’s DevTools.
For instance, you can check the return type of the elements
variable above with console.log(elements);
which returns the following value in the web console (in Chrome DevTools):
A Better Example of Using the DOM API
It frequently happens that the DOM API provides more than one solution for the same task. So, it’s always a good idea to ask whether we have used the best solution. For instance, in the example above we didn’t; we changed the style using JavaScript, which goes against the separation of concerns (SoC) software design principle.
It would be much more effective, both performance- and workflow-wise, if we added a class dynamically to each anchor tag we want to change the color of, then add the style rules using CSS. Luckily, the DOM has a solution for this, respectively the Element.classList.add()
method that we can use on every object that inherits from the generic Element
object.
The above example looks like this using this method:
// selects all 'a' elements on the page let elements = document.querySelectorAll('a'); // loops through the elements variable for (let i = 0; i < elements.length; i++) { // adds the 'dynamic-color' class to each element elements[i].classList.add('dynamic-color'); }
Then, we can add the color with CSS:
.dynamic-color { color: magenta; }
Much nicer, I think. It’ll also be easier to change the link color if we want to.
Next Steps
Here ends our high-level overview of how the DOM API works!
To understand it better, have a look at my other articles on this subject: one about event listeners that let you bind dynamic functionality (e.g. the link color change in the example above) to events (e.g. a click) and another one about how to convert jQuery to JavaScript using the DOM API.
-
JavaScriptAn Introduction to JavaScript Event Listeners for Web Designers
-
JavaScriptEssential Cheat Sheet: Convert jQuery to JavaScript
The Mozilla Developer Network also has great explainer articles, such as their Introduction to the DOM tutorial and the HTML DOM API page that explains how to use interfaces belonging to HTML element nodes.
No comments:
Post a Comment