Week 5 - Document Object Model
All the JavaScript that we have read up until this point could be run either in the browser or with NodeJS. It has been Core JavaScript which works the same in both places.
On top of core JavaScript it depends on which engine you are using. In the browser we have access to the Web APIs. In NodeJS there are a bunch of Node APIs.
Running JavaScript in the Browser
Section titled “Running JavaScript in the Browser”You can attach one or more JavaScript files to your your webpage by using a <script>
tag.
<script src="myscript.js"></script>
The recommended place to initially add your scripts is inside the body element, after all your other HTML.
<body> <p>Some content</p> <script src="myscript.js"></script></body>
OR what we will be doing in the near future, so you should start doing it now, is putting all your script tags inside the <head>
and adding the type="module"
attribute. This will allow us to import scripts.
<html> <head> <script src="myscript.js" type="module"></script> <!-- wait until the DOM has loaded & script will be a protected module --> <script src="myscript.js" defer></script> <!-- wait until after the DOM has loaded --> </head> <body></body></html>
Running JS in the browser
Another recommended feature that you can add to your script tag is the defer
attribute. This will tell modern browsers to wait until all your HTML has loaded before trying to run your script. The type="module"
attribute mentioned above has the same effect as the defer
attribute.
defer and async
Multiple Files and Scope
Section titled “Multiple Files and Scope”If you add multiple JavaScript files to the same HTML file they will, by default, all be able to see each other’s code. If you declare a variable or function in one of the files then the other file will be aware of them. All the code from each of the files will be loaded into the same global scope.
The exception to this is if you are using ES Modules. This is a recent but fully supported feature added in the last few years. You can add type="module"
to your initial JavaScript file <script>
tag, and then it will be able to import other files as modules. Each JavaScript file module will have it’s own scope.
Here is a quick simple example of the import process. Say we have an HTML script tag that loads main.js
.
<script src="js/main.js" type="module"></script>
Then, inside the main.js
file we can import a file from the same directory called awesome.js
.
import { message } from './awesome.js';//import a function called message from inside file
message('Emma');//call the function after it is imported
Inside the awesome.js
file we have to explain that the message
function is allowed to be exported.
function message(name) { console.log(`${name} is awesome!`);}
export { message };
We can export
any variables and functions that we want from a JS file. Then the variables and functions can be import
into any file, as long as the file doing the importing was loaded by the HTML file with type="module"
.
We will be talking about modules a lot more later in the semester as our code becomes more complex.
Document Object Model
Section titled “Document Object Model”When the browser reads an HTML file it creates an Object model representing all the content on the page. It builds a tree structure that helps it to know which elements are nested inside each other, which elements are parents and which are children.
This is a visual representation of how a browser sees the page. You can think of each indent as the start of a new branch in the DOM tree. Inside the html
object, there are two children - head
and
body
. Inside the head are two more children - title
and link
. title has a child, which is #text
. The link
element has no children. Inside body
> header
> h1
there are two children -
img
and #text
. The img
and the #text
are siblings.
doctypehtml head title #text link body header h1 img #text nav a #text a #text a #text main h2 #text p #text footer p #text
You need to be able to visualize every page in this manner. Understand when you are searching for things or altering things that you will be working with parents, children, and siblings.
One of the things that sets NodeJS and JavaScript in the browser apart is the DOM. NodeJS does NOT have access to the DOM.
The DOM is NOT part of core JavaScript.
The DOM is an add-on that browsers get as part of the window
object.
Everything you do in the browser, which is not part of core JavaScript, exists inside the window
object. Because of this, You can write window
as the first step in accessing an Object in the DOM
OR you can omit it.
window.alert('This is a pop up message');alert('This is also a pop up message');//both these lines access the same alert method
Nodes and Elements
Section titled “Nodes and Elements”Each one of the things listed above, in the DOM diagram, is a Node
. There are several kinds of types of nodes, including ElementNode
, TextNode
, DocumentFragment
, and Comment
. There are others but these are, by far, the most common.
ElementNode
s are the tags that you write in your HTML document.
TextNode
s are the strings that you write between the opening and closing tag in your HTML document.
There are JavaScript node properties and methods which work on all the types, some that work only on Element nodes, and some that work only on Text nodes.
Attributes
Section titled “Attributes”Inside any DOM ElementNode you can add or read attributes. Many of the attributes that you write in your HTML will have a corresponding attribute in JavaScript. Eg: if your element in the HTML has an id
attribute, then when you reference that element in your JS, it will have an id
property.
There are a few exceptions to the naming of the properties. The most notable is the class
attribute in HTML. In JavaScript, you have to use the property name className
because class
is a reserved keyword.
There are also dataset
properties, which are properties that you can invent and insert into the HTML. These attributes all have a name that begins with data-
.
<p data-me="steve" data-time="3pm">This paragraph has dataset attributes.</p>
In JavaScript we can add attributes, update the value of attributes, check if attributes exist, read the value of attributes or remove attributes. We will talk more about these methods soon.
The Document Object
Section titled “The Document Object”One of the objects inside window
that you will access most is the document
object. It contains all the methods and properties for working with HTML and CSS through JavaScript.
let h = document.querySelector('h1');//find the first h1 element on the pageconsole.log(h.textContent);//output the #text inside the h1 element.
We could, but typically do not, put window
in front of the document.querySelector
command.
Intro to the DOM
It is important to remember that there are two main types of Nodes in the DOM - TextNodes and ElementNodes.
Some of the properties and methods that you use will be looking at Nodes
and some will be looking at ElementNodes
. The general object type Node
refers to both kinds, whereas Element
nodes
refer just to the tags like <p>
or <div>
or <ul>
.
When you look at the tree structure created as the DOM, this distinct is important. In the following example, the <div>
element has TWO children
, but FIVE childnodes
. The carriage return and
spaces that come after <div>
, </h2>
, and </p>
count as text nodes and therefore are childnodes
.
<div> <h2>A Heading</h2> <p>a paragraph</p></div>
The <h2>
and <p>
element each have 1 children
and 1 childnode
.
Nodes vs Elements
Nodelists vs HTMLCollections
ChildNodes vs children
Finding Elements in HTML
Section titled “Finding Elements in HTML”A task that you will frequently do in JavaScript is locating parts of your webpage so you can read the content or update the content. Eg: Find the sidebar so you can add new links. Find the main
<ul>
so you can add a new list of products.
Traversing the DOM
Finding HTML Elements
querySelector, querySelectorAll, and getElementById
Section titled “querySelector, querySelectorAll, and getElementById”The two methods we use the most to find elements on the page are document.querySelector
and document.querySelectorAll
. The difference between them is that querySelector
finds the first match starting at the top of the page and querySelectorAll
finds ALL the matches.
If you want to change content on the page, find out what the content inside an element is, move an element, or delete an element then you need to find it first.
let p = document.querySelector('p');//find the first paragraph on the pagelet ps = document.querySelectorAll('p');//find ALL the paragraphs on the page
The querySelector
method will return a single ElementNode
.
The querySelectorAll
method will return a NodeList
. A NodeList
can be thought of as an Array of ElementNodes.
When you want to make changes to a webpage or read the contents of a webpage with JavaScript then you need a way of locating elements. The three methods that you will use most frequently when accessing web page content are:
let element = document.querySelector(cssSelector); //returns a single element nodelet nodes = document.querySelectorAll(cssSelector); //returns a NodeListlet element = document.getElementById(id); //returns a single element node
querySelector( )
and getElementById( )
search the webpage for the first element node that matches.
let anchor = document.querySelector('.main p a');
In the example above, the variable anchor will contain either null, if no match found, or the first anchor tag inside a paragraph inside an element with the className .main
. You can pass ANY valid CSS selector, as a string, to this method.
let foot = document.getElementById('footer');
In this example, the variable foot will contain either null or the element on the page that has the id footer
. You pass any string that should match an id of an element on your page.
querySelectorAll( )
will return a NodeList
, which is similar to an Array in that it is a numbered list, but it can only contain HTML Nodes. When you call querySelectorAll( )
, it will ALWAYS return a NodeList. The NodeList might be empty, but it is still a NodeList with length zero.
let paragraphs = document.querySelectorAll('#main p');
The above example will return a NodeList containing ALL of the paragraphs inside the element with the id main
. Notice that this is a valid CSS selector, just like the querySelector( )
call above.
If you want to loop through all the elements inside of paragraphs
, you could use a for loop
.
Alternatively, a NodeList
has a forEach
method that works just like the Array forEach
method.
let paragraphs = document.querySelectorAll('#main p');
//regular function versionparagraphs.forEach(function (p, index) { p.textContent = `Paragraph ${index} updated by the first forEach`;});
//arrow function versionparagraphs.forEach((p, index) => { p.textContent = `Paragraph ${index} updated by the second forEach`;});
There are a couple other methods that can be used to get a list of elements - getElementsByTagName()
and getElementsByClassName()
. As the names imply you would give a tag name or a class name to find the matches. These methods existed before querySelector
and querySelectorAll
were added to JavaScript and it is rare to find them actually used.
Parents, children, and Siblings
Section titled “Parents, children, and Siblings”If you had a variable called someElement
you could use any of the following properties.
someElement.parentElement
Get the parent element that wraps someElementsomeElement.childNodes
Get a list of all the text and element children of someElementsomeElement.children
Get a list of all the element children of someElementsomeElement.nextSibling
Get the text or element sibling that comes after someElementsomeElement.nextElementSibling
Get the element sibling that comes after someElementsomeElement.previousSibling
Get the text or element sibling that comes before someElementsomeElement.previousElementSibling
Get the sibling element that comes before someElementsomeElement.firstElementChild
Get the first element child of someElementsomeElement.lastElementChild
Get the last element child of someElement
Finding Parent Elements
closest and matches
Adding HTML to a Page
Section titled “Adding HTML to a Page”There are a number of ways that you can create new content on a webpage. The two main approaches are:
- You can create Elements with the
document.createElement()
method and text nodes with thedocument.createTextNode()
method. After creating the elements you can add attributes likeclassName
. With different nodes created, you can use theappend()
orappendChild()
method to build whatever tree structure you want. - You can create a String that contains whatever HTML you would write if you were putting it in the HTML file. Then, with the
append()
orsetHTML()
methods or theinnerHTML
property you can convert the string into actual nodes in your page. Template strings are commonly used for this approach. - An HTML template can be created and cloned. We will look at this approach more after we cover fetching remote data.
The createElement() Approach
Section titled “The createElement() Approach”The createElement
method will create any HTML element you need. Just pass in the name of the tag and it will return a new element of that type.
The createTextNode
method will create a text node. Just pass in the string that you want to use as the text and it will return the new text node.
There is also a createDocumentFragment()
method that lets us create a self-removing wrapper for chunks of HTML that will will inject into the page. More about this later.
let p = document.createElement('p'); //creates an Element Node of the type providedlet txt = document.createTextNode('hello world'); //creates a TextNodelet df = document.createDocumentFragment(); //creates a Document Fragment
The elements can have attributes too. For most attributes the common approach is to use the property of the same name.
Let’s use this HTML as the example of what we want to create. We will assume that the main
element is already in our HTML file and we want to create and add all the content inside it.
<main> <div class="header"> <h2>Some Heading</h2> </div> <div class="content"> <p><img src="./img/logo.png" alt="Company logo" /> Lorem.</p> <p>Ipsum.</p> </div></main>
Here is the JavaScript that will create everything inside the <main>
element.
let main = document.querySelector('main');//create the elementslet header = document.createElement('div');let content = document.createElement('div');let h2 = document.createElement('h2');let p1 = document.createElement('p');let p2 = document.createElement('p');//approach one to create the text nodelet lorem = document.createTextNode(' Lorem.');//approach two is to use the .textContent propertyp2.textContent = 'Ipsum.';let img = document.createElement('img');//add the attributesheader.className = 'header';content.className = 'content';img.src = './img/logo.png';img.alt = 'Company logo';//then start with the innermost nodes and start appending//if you didn't use p2.textContent then you need to append a textNode// p2.appendChild(ipsum); //appendChild can only accept one child at a time// appendChild can be used to append a child TextNode or a child ElementNodep1.append(img, lorem); //the order is important. append can accept multiple childrencontent.append(p1, p2);header.append(h2);main.append(header, content);//appending to main is the last step because this adds it to the page
The HTML String Approach
Section titled “The HTML String Approach”The HTML String approach is the alternative to creating elements. Instead we are writing out the whole string and then asking the browser to do the work of parsing all the elements and appending them at the same time.
Here is the String approach for the same content.
let main = document.querySelector('main');//use a template string incase you have variables that you want to embedded in the string.let myhtml = `<div class="header"> <h2>Some Heading</h2> </div> <div class="content"> <p><img src="./img/logo.png" alt="Company logo" /> Lorem.</p> <p>Ipsum.</p> </div>`;
main.innerHTML = myhtml;//alternativemain.setHTML(myhtml);
It is important to note that this approach is going to replace any content that is already inside of <main>
and not just append it to the existing content.
Updating and Removing HTML
Section titled “Updating and Removing HTML”Manipulating HTML can be done quite easily once you understand the parent-child-sibling relationship between Nodes and the difference between Element nodes and Text nodes.
Once you have found the ElementNode you need, then you can start to manipulate the content.
let content = document.querySelector('p.first');//find the first paragraph with the class "first".content.textContent = 'The new paragraph content';//change the text inside the paragraphlet main = document.querySelector('main');//find the main elementlet p = document.createElement('p');//create a new paragraphp.textContent = 'A new paragraph for the page';//add some text inside the paragraphmain.appendChild(p);//add the newly created paragraph as the last child of the main element
It is important to note that both the append
and the appendChild
methods always inject the new child element or child textNode as the LAST child. It will always be added at the bottom of the parent element.
Adjacent DOM Manipulation
More methods for manipulation
If you want to inject your new textNode or element in a location other than the last position, then you need to use the insertBefore()
, insertAfter()
, insertAdjacentElement()
, insertAdjacentText()
, or insertAdjacentHTML()
methods. The insert before and after methods want a reference element as well as the child node to insert before or after. The insertAdjacent methods
want a reference element plus one of four reference positions. Take this HTML as an example:
<h2>Some heading</h2><ul> <li>first item</li> <li>second item</li> <li>third item</li></ul><p>Some more text</p>
If the <ul>
is my reference element, I can inject my new element in one of the four positions:
- before the
<ul>
starts beforebegin - after the
<ul>
starts but before the first<li>
afterbegin - after the last
<li>
but still inside the<ul>
beforeend - after the
<ul>
ends but before the<p>
afterend
The four strings used as the position values are bolded in the list above.
referenceElement.insertAdjacentElement(position, childElement); //insert ElementreferenceElement.insertAdjacentText(position, childTextNode); //insert textNodereferenceElement.insertAdjacentHTML(position, HTMLString); //parse string and insert
InsertBefore and insertAdjacentElement
Side Effects of Appending
Section titled “Side Effects of Appending”It is worth noting, when you create an element with createElement
or reference and element with querySelector
or the other methods, then that element still exists whether it is just in memory or on the page.
let p = document.createElement('p'); //exists in memoryp.textContent = 'I exist!'; //p is still in memory onlylet header = document.querySelector('header'); // exists on the pagelet main = document.querySelector('main'); // exists on the pagelet footer = document.querySelector('footer'); // exists on the page
When you call the append
or appendChild
or remove
or removeChild
methods you are actually MOVING the element. You are moving it from memory to the page, from the page to memory, OR from one location in the page to another.
header.append(p); //moved p from memory to inside header on pagemain.append(p); //moved p from inside header to inside mainfooter.append(p); //moved p from inside main to inside footerfooter.removeChild(p); //moved p from inside footer on page to in memory
The above code sample does NOT create three copies of the paragraph.
If you did want to create copies of the paragraph then you could use the cloneNode
method.
let copy1 = p.cloneNode(true); //creates a copy of p and includes anything it containedlet copy2 = p.cloneNode(true); //creates a copy of p and includes anything it contained//now we have p, copy1, and copy2 as three separate elements
Removing Content
Section titled “Removing Content”If you want to remove HTML that already exists we have a few options.
- With the
innerHTML
property or thetextContent
property you can set the content of any element to an empty String.
let div = document.querySelector('div'); //find the first div on the pagelet p = div.querySelector('p'); //find the first paragraph inside div
p.textContent = ''; //set the text inside the paragraph to emptydiv.innerHTML = ''; //remove all html and text inside div. could also use .setHTML()
- Using the
remove()
orremoveChild()
methods.
p.remove(); //will remove the paragraph from whatever its parent is.div.remove(); //will remove div and everything it containsp.parentElement.removeChild(p); //refer to the parent of the p and use removeChild to target what will be removeddiv.removeChild(p); //remove the paragraph from it's parent div
Difference between remove and removeChild
Node Properties
Section titled “Node Properties”In the list below there are a series of property pairs. The first properties will return a NodeList or a single Node. Remember that Nodes can be element nodes, text nodes, or comments. The second property will return a list of Element Nodes or a single Element Node.
- node.childNodes v node.children
- node.firstChild v. node.firstElementChild
- node.lastChild v. node.lastElementChild
- node.nextSibling v. node.nextElementSibling
- node.previousSibling v. node.previousElementSibling
- node.parentNode v. node.parentElement
These last three node properties return a single piece of information about the node.
node.nodeName; //returns the tagname, if an element nodenode.nodeType; //returns the integer referencing the type of node. Eg: 1=element, 3=textnode.nodeValue; //returns the string inside a text node
Node Methods
Section titled “Node Methods”parentNode.appendChild(newNode); //add a new child node inside the parentparentNode.removeChild(childNode); //remove the child from the parentnode.replaceChild(newNode); //replace one node with a new oneparentNode.contains(node); //checks if the node is a descendant of the parentnode.hasChildNodes(); //returns a boolean indicating if the node has child nodesnode.hasAttributes(); //returns a boolean if the node has attributesparentNode.insertBefore(newNode, referenceNode); //inserts a new node into the DOM//immediately before the reference node
More DOM methods
Injecting Strings into HTML
Creating HTML Content with JS
Element Properties
Section titled “Element Properties”Here is a list of common properties that map to attributes in the HTML as well as some methods that you could use to manipulate the CSS classes assigned to an element.
let c = element.className; //get or set the value of the class attribute//one string with all the class names
let list = element.classList; //get the list of css classnames assigned to the element (a DOMTokenList)element.classList.add(className); //add a new css class to the listelement.classList.remove(className); //remove a single css class from the listelement.classList.replace(oldClassName, newClassName);element.classList.contains();element.classList.toggle(className); //remove if exists, add if it doesn't exist
let nm = element.tagName; //retrieve the HTML element's tag name eg: P, LI, A, DIV
element.href = 'http://www.example.com';element.src = 'http://www.example.com/photo.jpg';element.id = 'bob';element.title = 'mouseover text';element.alt = 'alternate description for image'; //accessibility matterselement.style = 'display:none;'; // create an inline style. Not recommended.
Element Attributes
Section titled “Element Attributes”There are a few specific methods for working with HTML attributes.
let main = document.querySelector('main'); //first main element on pagelet img = document.querySelector('img'); //first image element on pagelet mi = main.querySelector('main img'); //first image element inside main
mi.setAttribute('src', 'http://www.example.com/photo.jpg'); //set the image's src attributelet title = mi.getAttribute('title'); //retrieve the value of the title attributelet hasAlt = mi.hasAttribute('alt'); //boolean indicating if the img has an alt attributemi.removeAttribute('href'); //remove the href attribute if it exists
Dataset Properties
Section titled “Dataset Properties”Having the ability to create your own custom attributes can be a very useful tool and allow you to store things like product reference ids in the HTML. To address this need, HTML5 standardized an approach to inventing custom attributes - called dataset properties.
You are allowed to create your own HTML attributes in the HTML or through JavaScript as long as their name starts with data-
. Here is an example of what the HTML would look like.
<p data-price="22.33" data-id="a57dd55d7d8d" data-link="http://abc.io/product">Some product information</p>
And here is the JavaScript that would create that same HTML.
let p = document.createElement('p');p.setAttribute('data-price', '22.33');p.setAttribute('data-id', 'a57dd55d7d8d');p.setAttribute('data-link', 'http://abc.io/product');document.body.append(p);//document.body points to the <body> element
It should be noted that ALL dataset property values are strings. If you want to store a numeric or boolean value in a data-set property, that is fine, but you will have convert the value to number or boolean after extracting it.
let priceTxt = p.getAttribute('data-price'); //extract the attribute valuelet price = parseFloat(priceTxt); //convert from string to number
Document Fragments
Section titled “Document Fragments”A documentFragment
is similar to an HTML element in that it can contain other HTML Elements and text nodes. The difference is that they only really exist in memory. They do not appear on the page.
We can use them to transport HTML from memory to the webpage.
Think of the HTML that you want to add to your page as a bunch of sand. The documentFragment
is a bucket used to hold the HTML and carry it to the page. When you get to the page, the HTML is dumped
out of the bucket on to the page.
let df = new DocumentFragment(); //version one of creating a document fragmentlet dfAlt = document.createDocumentFragment(); //version two. Both work
let p = document.createElement('p');let h2 = document.createElement('h2');h2.className = 'mainTitle';h2.textContent = 'The Heading';p.textContent = 'Lorem Ipsum';df.append(h2, p); //now the h2 and paragraph are inside the document fragment
document.body.append(df); //now the h2 and paragraph are on the page//but the document fragment is still only in memory//the h2 and paragraph were transfer from memory to the body element.
DOM manipulation with DocumentFragments
Dynamic HTML Best Practices
Section titled “Dynamic HTML Best Practices”When you are dynamically creating content for your webpages, you will frequently be looping through an Array of Objects to get the content. Each of the objects will have properties with the same property names. You will take the values of those properties and inject them into the HTML that you are creating.
Let’s say that this is your data which you will use to create the new HTML.
let info = [ { id: 'a6f7', txt: 'Told ya' }, { id: 'b5f7', txt: 'Not real data' }, { id: 'c2f7', txt: 'But it looks like it' }, { id: 'a1f4', txt: 'And works like it' }, { id: 'a6ee', txt: 'So we will use it' },];
Now, use the Array map
method to loop through the Objects and build an HTML String.
When the String is fully built, call one of the methods or properties to inject the content once.
//version one// use the Element.setHTML() method to append a string that includes HTMLlet one = document.querySelector('.one');let html = info .map((item) => { let str = `<p data-ref="${item.id}">${item.txt}</p>`; return str; }) .join('');one.setHTML(html);
//version two// use the innerHTML property to append a string that includes HTMLlet two = document.querySelector('.two');let html2 = info .map((item) => { let str = `<p data-ref="${item.id}">${item.txt}</p>`; return str; }) .join('');two.innerHTML = html2;
//version three//use the DOMParser parseFromString method to convert a string to an HTML document// and then append the document's body property valuelet three = document.querySelector('.three');let html3 = info .map((item) => { return `<p data-ref="${item.id}">${item.txt}</p>`; }) .join('');let parser = new DOMParser();let doc = parser.parseFromString(html3, 'text/html');three.append(doc.body);
//version four// use createElement followed by append to create an array of HTML elements// then use Element.append( ...theArray ) with the spread operator to append the array of Elementslet four = document.querySelector('.four');let html4 = info.map((item) => { let p = document.createElement('p'); p.append(item.txt); p.setAttribute('data-ref', item.id); return p;});four.append(...html4);// four.append( html4[0], html4[1], html4[2], html4[3] );
The same process can be done using the createElement
method and wrapping everything inside a documentFragment
. The documentFragment
holds all the new HTML in memory and is used to transport all
the new HTML to the page. Once the new HTML has been loaded in the page, the documentFragment
removes itself and leaves behind the new HTML.
DOM style, className, classList
Section titled “DOM style, className, classList”If you want to dynamically style your web page content there are three properties that belong to every Element Node.
style
className
classList
The style
property lets you set the value of any single CSS property on any Element. Inside the style
property is a list of every CSS property name. However, the names are slightly different. Any
CSS property name that includes a hyphen, like background-color
, will be written as a single camel-case name - backgroundColor
.
Every value is a string and needs quotation marks.
let elem = document.querySelector('p'); //get the first paragraphelem.style.border = '1px solid red';elem.style.backgroundColor = 'khaki';
The className
property lets you set the contents of the HTML attribute class=""
. We can’t use class
as an HTML attribute from within JavaScript, because class
is a reserved keyword.
let elem = document.querySelector('p'); //get the first paragraphelem.className = 'big red content';
The classList
property is a DOMTokenList
, which is similar to an Array of all the values inside the HTML class=""
attribute. The classList
property has a series of methods that we can call to
manage and update the list of values.
let elem = document.querySelector('p'); //get the first paragraphelem.classList.add('active'); // add the class `active` to the HTMLelem.classList.remove('active'); // remove the class `active` to the HTMLelem.classList.toggle('active'); // add the class `active` to the HTML if it doesn't exist, remove if it does.elem.classList.contains('active'); // check IF the class `active` is assigned to the elementelem.classList.replace('active', 'inactive'); // replace the class `active` with the class 'inactive'
The classList
methods are the most efficient way to update your DOM element styling and are considered the best practice over style
or className
.