HTML DOM
Finding elements
let el = document.getElementById('element-id');
el = document.querySelector('#element-id'); // Use CSS selectors. Returns the first matching element (in this case, same as above).
const divs = document.getElementsByTagName('div'); // Returns an HTMLCollection
const htmlCol = document.getElementsByClassName('class-name'); // Returns an HTMLCollection
const nodeList = document.querySelectorAll('.class-name'); // Returns a NodeList. Use the . CSS selector for classes.
Navigating Node Relationships
// These are properties
el.parentNode
el.children // Returns an HTMLCollection
el.childNodes // Returns a NodeList
// Navigating all node types
el.firstChild // Could return a text node, for example
el.lastChild
el.nextSibling
el.previousSibling
// Navigating elements only
el.firstElementChild
el.lastElementChild
el.nextElementSibling
el.previousElementSibling
Differences berween HTMLCollection and NodeList.
- They are both like arrays, but they don't have array methods like
pop,push, etc.NodeListdoes have aforEachmethod. HTMLCollectiononly contains elements (a subset of nodes).NodeListcontains all types of nodes.HTMLCollectionis a "live" collection, that gets updated if the DOM changes.NodeListis a static collection.
Modifying an element
element.innerHTML = ''; // The string can be some new HTML
element.id = 'unique-id';
element.style.color = 'red'; // Style fields are camel-cased versions of CSS properties
element.classList.add('class-name');
element.classList.remove('class-name');
element.setAttribute('attribute-name', value);
element.setAttribute('stand-alone-attribute', '');
element.removeAttribute('attribute-name');
element.builtInProperty = value; // This only works for certain properties (not all attributes)
Adding and Deleting elements
// Always create on the document
const div = document.createElement('div');
const textNode = document.createTextNode("Some text");
div.appendChild(textNode);
const p1 = document.createElement('p');
p1.innerHTML = 'P1';
const p2 = document.createElement('p');
p1.innerHTML = 'P2';
div.appendChild(p1); // Returns the appended child (p1)
div.replaceChild(p2, p1); // (new, old)
div.removeChild(p2);
// or
p2.remove();
// Make it part of the DOM by appending to an element
// already on the DOM or to the document directly
// NOTE: Only one element on document allowed.
document.appendChild(div);
div.insertBefore(/* newNode */, /* relativeToNode */);
div.insertAdjacentText(/* position */, /* string */);
div.insertAdjacentHTML(/* position */, /* HTML string */);
div.insertAdjacentElement(/* position */, /* newNode */);
Position takes the following values:
| value | meaning |
|---|---|
'beforebegin' | Before the target element |
'afterbegin' | Inside the target element, before its first child |
'beforeend' | Before the target element, after its last child |
'afterend' | After the target element |
Other properties of nodes/elements
// Assuming empty document
const div = document.createElement('div');
document.appendChild(div);
div.nodeName // 'DIV'
div.nodeValue // null - always null for elements
div.childElementCount // 0
div.hasChildNodes() // false
div.childNodes.length // 0
Event Handling
Bubbling: Event is handled by the inner element first, moves to the ancestors
Capturing: Event is handled by the element fist before moving to descendants
function someFunction(event) {
event.preventDefault(); // Only if you want to prevent default behavior
}
// useCapture is optional. If true, use capturing, otherwise use bubbling.
element.addEventListener('click', someFunction, useCapture);
element.removeEventListener('click', someFunction, useCapture);
An event handler for a specific element can be specified as an attribute on an element using the on prefix, such as onclick. The value of the attribute is actual JavaScript, with this being the element. See forms section for an example. List of event attributes.
Inputs
Forms
<form action="/endpoint" method="post">
<fieldset>
<legend>Applicant</legend>
<label for="name">Name</label>
<input type="text" name="name" required>
<label for="age">Age</label>
<input type="number" name="age" min="13" max="120">
</fieldset>
<fieldset>
<legend>Loan</legend>
<label for="amount">Amount</label>
<input id="loan-amount" type="number" name="amount" min="50000" max="1000000" required>
<label for="term">Term</label>
<select name="term">
<option value="15">15 Years</option>
<option value="20">20 Years</option>
<option value="30">30 Years</option>
</select>
</fieldset>
<input type="submit" value="Submit" onclick="console.log('submit')">
</form>
More form elements at w3schools.com
Form validation:
const input = document.getElementById('loan-amount');
if (!input.checkValidity()) { // checkValidity is also available on a form element
input.validationMessage // string
input.validity.rangeUnderflow // boolean
input.validity.rangeOverflow // boolean
input.validity.valueMissing // boolean
}
Scripts
<script> element attributes:
| attribute | description |
|---|---|
async | won't block parsing, will be executed ASAP when script is available (loaded in parallel) |
crossorigin | Allow error logging for sites which use a separate domain for static media |
defer | (Not to be used with inline) Execute after document is parsed but before DOMContentLoaded |
fetchpriority | high, low, auto |
integrity | user-agent can verify the integrity of the script |
nomodule | Script shouldn't be executed if ES2015 is supported. (Allows fallback for older browsers) |
nonce | A value generated by the server for CSP |
referrerpolicy | The value of the Referer header when fetching the script. Default: strict-origin-when-cross-origin |
src | The URI for imported script |
type | Mime-type, module, or any data block (src will be ignored) |
Module fallback example:
<script type="module" src="main.js"></script>
<script nomodule src="fallback.js"></script>
Embed data in HTML
<script id="data" type="application/json">{ "key": "value" }</script>
<script>
const data = JSON.parse(document.getElementById('data').text);
</script>
Links
Examples:
<link href="main.css" rel="stylesheet">
<link href="mobile.css" rel="stylesheet" media="screen and (max-width: 600px)">
<link href="favicon.ico" rel="icon">
<link href="myFont.woff2" rel="preload" as="font" type="font/woff2" crossorigin="anonymous">
Templates
<div id="container"></div>
<template id="template">
<div>Click me</div>
</template>
const isSupported = 'content' in document.createElement('template');
// If supported:
const div = document.getElementById("container");
const template = document.getElementById("template");
const clone1 = template.content.cloneNode(true);
div.appendChild(clone1);
// NOTE: Clone an actual element inside the template if you need event handling
const clone2 = template.content.firstElementChild.cloneNode(true);
clone2.addEventListener("click", () => {}));
div.appendChild(clone2);
You can use named <slot>s inside a template.
Events
| category | elements | events | event properties |
|---|---|---|---|
| Form | <form> | formdata, reset, submit | |
| Input | <input>, <select>, <textarea> | input, invalid, search, selectionchange | |
| Keyboard | keydown, keyup | altKey, ctrlKey, metaKey, shiftKey, key | |
| Mouse | click, dblclick, mouseup, mousedown |
For input event, the event.data property has the last character typed if inputType is 'insertText'. It's null if input type is 'deleteContentBackward' or 'insertFromPaste'.
Important properties
- event.
bubbles, - event.
cancelable - event.
composed - event.
currentTarget- The current object which the event will be sent. May have changed due to "retargeting" - event.
isTrusted - event.
target- The object which the event was originally dispatched - event.
type
Important methods:
- event.
stopPropagation() - prevent any parent handlers from being executed - event.
stopImmediatePropagation() - prevent any parent handlers and also any other handlers from executing - event.
preventDefault() - If event is cancellable - element.
dispatchEvent(constructedEvent);
Notes:
- Depending on the framework used, returning false in an event handler may effectively call one or more of these methods.