Document Object Model (DOM)

Selecting DOM Elements

Get Element(s)

Get element nodes for HTML tag, class, or id

document.body
document.getElementsByTagName("p");
document.getElementsByClassName("class");
document.getElementById("id");

Query Selector

returns the first instance for this query

document.querySelector("div.selected")

returns a node list of elements for this query

document.querySelectorAll(".selected")

// convert node list to array
const list1 = Array.from(document.querySelectorAll(".element"));
const list2 = [...document.querySelectorAll(".element")];

Matches query

e.target.matches("div")

Accessing element node's properties

Nodes

const element = document.createElement("span");
const text = document.createTextNode("hallo")

element.parentNode
element.parentElement

element.firstChild
element.lastChild
parent.append("Hello from JS")
parent.append(element)
parent.appendChild(element)
element.remove()
parent.removeChild(element)

element.innerHTML
element.textContent // text including whitespace from HTML structure
element.innerText   // simple text
element.content

element.value

element.tagName // == 'SPAN' || == 'VIDEO'
element.nodeType // == Node.TEXT_NODE || == Node.ELEMENT_NODE

insertAdjacentHTML

const childHTMLString = "<img src='bird.png' alt='bird'>";
parentElement.insertAdjacentHTML("beforeend", childHTMLString);
element.replaceWith(node)

textContent

document.getElementById("gamebutton").textContent = "Restart Game!";

content

const templateContent = document.getElementsByTagName("template")[0].content;

appendChild

const childImage = document.createElement("img");
childImage.src = "butterfly.png";
parent.appendChild(childImage);

cloneNode

const template = document.createElement("template");
template.innerHTML = `<h3>Title</h3>`;
const node = template.content.cloneNode(true);

Node

document.createTextNode(text)
node.textContent = '123'
nodeA.parentNode.insertBefore(nodeB, nodeA)             // nodeB - nodeA
nodeA.parentNode.insertBefore(nodeB, nodeA.nextSibling) // nodeA - nodeB = insertAfter (which does not exist)

node.after(document.createElement('span'))

Attributes

element.setAttribute("tabindex", -1)
element.getAttribute("src")
element.removeAttribute("class")

// image attributes
element.src
element.alt

// data attributes – <span data-index="1" data-vegetable-variety="spinach">Spinach</span>
element.dataset
element.dataset.index
element.dataset.vegetableVariety

Classes

element.className
element.classList.add("new-class")
element.classList.add("mystyle", "anotherClass", "thirdClass")
element.classList.remove("highlight")
element.classList.contains('zoom')
element.classList.toggle("switched-on")
element.classList.toggle("switched-on", false)
element.classList.toggle("switched-on", el.width > 120)
element.classList.value
element.classList.length
element.classList.item(0)

Style

element.style.display = "block";
element.style.border = "1px solid blue";
element.style.marginLeft = 0;
element.style.animationPlayState = `paused`;
element.style.setProperty("background", "#fff");
element.style.setProperty("--cursorY", e.offsetY + "px");
element.style.removeProperty("--cursorY");

document.documentElement.style.cssText = `color: red;`;

const computedStyle = window.getComputedStyle(element);
computedStyle.getPropertyValue('margin')

StyleSheets

document.styleSheets /* – stylesheets associated with a page */
document.styleSheets[0].cssRules
document.styleSheets[0].cssRules[0].type
document.styleSheets[0].cssRules[0].deleteRule(rule)
document.styleSheets[0].cssRules[0].appendRule(rule)

DOM Traversal

element.parentNode
element.nextSibling
element.firstChild
element.lastChild
element.closest('button:not(.user)')
element.closest('dialog')

Cloning a node (pass parameter true for deep copy)

const clonedNode = document.querySelector("#picture_template").cloneNode(true);
parent.appendChild(clonedNode);

Measurements and Scroll

Screen Measurements

window.innerWidth
window.innerHeight
window.outerWidth
window.outerHeight

window.screenX
window.screenY
window.screenLeft
window.screenTop

window.pageXOffset
window.pageYOffset

window.scrollX
window.scrollY

window.screen // width, height, availWidth, availHeight, availLeft, availTop, isExtended, orientation

window.devicePixelRatio

Element Measurements

element.getClientRects() // more than one for e.g. inline-level elements
element.getBoundingClientRect().top // x, y, width, height, top, right, bottom, left
element.offsetParent // parent with position != `static`

element.offsetTop // `block`-level: position of border-box, `inline`-level: position of FIRST border-box
element.offsetLeft
element.offsetHeight
element.offsetWidth

jQuery's offset() in Vanilla JS

var rect = document.querySelector("#container").getBoundingClientRect();
var offset = { 
  top: rect.top + window.scrollY, 
  left: rect.left + window.scrollX, 
};
console.log(offset);
element.clientTop
element.clientLeft
element.clientHeight
element.clientWidth
document.elementFromPoint(x, y)

Scroll

window.scroll({ top: 100, behavior: "smooth" })

window.scrollTo({ top: 100, behavior: "smooth" })

window.scrollBy(dx, dy)
window.scrollBy({ top: 100, behavior: "smooth" })

element.scrollIntoView(true) // align to top
element.scrollIntoView(false) // align to bottom
element.scrollIntoView({ block: "start", behavior: "smooth" })
element.scrollIntoView({ inline: "center", behavior: "smooth" })

Text Manipulation

Writing to the document

document.write("");

Text Selection

Selection

const selection = window.getSelection();
const selection = document.getSelection();

selection.isCollapsed   // true / false
selection.empty()
selection.removeAllRanges()
selection.addRange(range)

selection.modify(alter, direction, granularity)
selection.modify("extend", "backward", "word")
selection.modify("extend", "forward", "word")
selection.modify("move", "forward", "line")
selection.modify("move", "forward", "lineboundary")
selection.modify("move", "forward", "character")


if (selection.type == "Range") return;
if (selection.type == "Caret") return;

Range

const range = selection.getRangeAt(0)

const range = new Range()
range.selectNodeContents(element)

range.commonAncestorContainer
range.startContainer
range.endContainer
range.startOffset
range.endOffset
range.collapsed   // true / false
range.setStart(node, offset)
range.setEnd(node, offset)

range.setStart(element, 12)
  • node – text node or an element node
  • If node is a text node, then offset must be the position in the text.
  • If node is an element node, then offset must be the child number.

Selection events

// attention: different behaviour on touch screens and desktops
document.addEventListener("selectionchange", function() {});

// better use pointer events for universal behaviour
document.addEventListener("mouseup", function() {});
document.addEventListener("touchend", function() {});
document.addEventListener("touchcancel", function() {});

Input and text fields

Select contents of a text field

document.querySelector("input").select();

Document Fragment

let fragment = new DocumentFragment()

for (let i = 1; i < 3; i++) {
   let li = document.createElement("li")
   li.innerHTML = i
   fragment.appendChild(li)
}

let list = document.querySelector("ul")
list.appendChild(fragment)

Separate HTML Document

const doc = document.implementation.createHTMLDocument();
doc.write('<div>'):
document.body.append(doc.body.firstChild);

// Stream HTML contents (div in the body will automatically update)
doc.write('<p>Hello'):
doc.write('world!</p>');
doc.write('<p>Yay!</p>');

doc.write('</div>'):

Event Listeners

window.addEventListener("load", () => alert("loaded DOM"));

For details see Event Listeners.

Mouse: click, contextmenu, dblclick, mousedown, mouseenter, mouseleave, mousemove, mouseover, mouseout, mouseup mousewheel, wheel,

Touch: touchstart, touchmove, touchcancel, touchend

Pointer: pointerdown, pointermove, pointerover, pointerout, pointerenter, pointerleave, pointerup

Gesture: gesturestart, gesturechange, gestureend

Keyboard: keydown, keypress, keyup

Device: devicemotion, deviceorientation, orientationchange

Frame: load, abort, error, beforeunload, unload, pageshow, pagehide, hashchange, resize, scroll

Form: change, input, select, focus, focusin, focusout, blur, invalid, reset, search, submit

Drag: drag, dragstart, dragend, dragenter, dragleave, drop

Animation: animationstart, animationend, animationiteration

Animation: animationstart, animationend, animationiteration, transitionend

Media: abort, error, waiting, canplay, durationchange, loadstart, loadedmetadata, canplaythrough, loadeddata, play, pause, playing, ended, progress, timeupdate, ratechange, seeked, seeking, stalled, suspend, volumechange

Misc: message, online, offline, popstate, show, storage, toggle,


Root object window

Properties

  • window.document
  • window.console

Methods

  • window.alert()

Properties of the window object don't need to be specified.

window.setTimeout(() => {
  window.alert("Hi");
}, 3000)
setTimeout(() => {
  alert("Hi");
}, 3000)

call parent function from within iFrame

parent = parent's window

// in document
function my_function() {
  // ...
}
// in iframe
parent.my_function()

Browser APIs

  • window.navigator
  • window.history
  • window.localStorage
  • window.sessionStorage
  • document.cookie

For details see Browser APIs.

Which Browser am I running on?

navigator.userAgent

Other useful details

navigator.appCodeName
navigator.appName
navigator.appVersion
navigator.cookieEnabled
navigator.platform
navigator.systemLanguage

Browser

Get all browser windows (not tabs)

await browser.windows.getAll()

DOMPoint and DOMMatrix

const point = new DOMPoint(10, 20)
const matrix = new DOMMatrix("translate(10px, 15px)").rotate(30)

matrix.transformPoint(point)

Draw a star mask

const createStar = ({ points = 5, x = 0, y = 0, size = 1 }) => {
  Array.from({ length: points * 2 }, (_, i) => 
    new DOMMatrix()
      .translate(x, y)
      .scale(size)
      .rotate((i / points) * 360)
      .translate(0, i % 2 ? -1 : -2)
      .transformPoint({ x: 0, y: 0 })
  )
}

function toCSSPolygon(points) {
  const pointsStr = points.map(point => `${point.x}px ${point.y}px`).join(', ')
  return `polygon(${pointsStr})`
}

const rect    = el.getBoundingClientRect() ;
const x       = rect.width / 2:
const y       = rect.height / 2;
const endSize = Math.sqrt(x**2 + y**2);
el.animate({
  clipPath: [
    toCSSPolygon(createStar({ x, y, size: 0 })),
    toCSSPolygon(createStar({ x, y, size: endSize })),
  ]
}, { duration: 500, easing: "ease-in" });

Feature detection

if (browser.contextMenus) {
  browser.contextMenus.create({ title: "Options...", ... })
}
if ("IntersectionObserver" in window) {
  // ...
}

setTimeout, setInterval and requestAnimationFrame

Functions

  • setTimeout(callback, timeout)
  • window.clearTimeout(myTimeout)
  • setInterval(callback, interval)
  • window.clearInterval(myInterval)
  • requestAnimationFrame(callback)

setTimeout

var to = setTimeout(timeoutDone, 3000);

function timeoutDone() {
  alert("Your three seconds are up!");
}

function someEventToCancelTheTimeout() {
  clearTimout(to);
}

setInterval

var myVar = setInterval(timer, 1000);

function timer() {
  var d = new Date();
  var t = d.toLocaleTimeString();
  console.log(t);
}

function stopFunction() {
  clearInterval(myVar);
}

requestAnimationFrame

function animationStep(time) {
   // do some animations
   
   requestAnimationFrame(animationStep);
}