12 JavaScript
True confessions: I don’t really know JavaScript (if you’re curious, I describe our relationship status here). Every now and again, though, I need it for a little something. So, let’s capture those moments for posterity.
12.1 What is DOMContentLoaded
?
DOMContentLoaded
is an event that fires when the HTML content is loaded and parsed.
Because the HTML on a page is loaded in the order in which it appears, your JavaScript won’t work if it’s trying to manipulate elements of the page before said elements are loaded (e.g. you can’t insertAdjacentHTML()
before you’ve loaded the relevant elements). If the JavaScript is in the head, it would by default try to run before the HTML below it.
To avoid this, you can add a structure with an event listener (using the addEventListener
method) around your code that waits for DOMContentLoaded
before running the JavaScript inside of the block.
document.addEventListener('DOMContentLoaded', () => {
...
; })
For external JavaScript, the same thing can be accomplished using the defer
attribute inside of the <script>
tag.
<script src="script.js" defer></script>
Adapted from Script loading strategies in MDN’s What is JavaScript?.
12.2 Template literals vs. strings
A template literal looks just like a string, but it is surrounded by backticks (`
) instead of single or double quotation marks ('
or "
).
// greeting is a template literal
const greeting = `Hello`;
// name is a "normal" string
const name = 'Chris';
When concatenating (i.e. joining together) strings with template literals, you can use variables wrapped in ${ }
, the values of which will be inserted in the results. For example
const greeting = `Hello, ${name}`;
console.log(greeting);
// output: "Hello, Chris"
Adapted from Handling text — strings in JavaScript: Concatenating strings in MDN’s JavaScript First Steps.
12.3 Expressions in strings
You can include JavaScript expressions in template literals, as well as simple variables, and the results will be included in the result:
const song = 'Danger Zone';
const artist = 'Kenny Loggins';
const score = 9;
const highestScore = 10;
const output = `I like the song ${song} by ${artist}. I gave it a score of ${score/highestScore * 100}%.`;
console.log(output);
// I like the song Danger Zone by Kenny Loggins. I gave it a score of 90%.
12.4 How to insert an HTML element
Scenario: I wanted to add a “skip link” to my (non-book) Quarto pages at the very top before the navigation bar (include-before-body
goes after the nav bar).
Solution: Use insertAdjacentHTML()
. It takes two arguments. The first, position
, can be one of the four following strings: "beforebegin"
, "afterbegin"
, "beforeend"
, or "afterend"
. The latter argument, text
, is the string to be parsed as HTML or XML and inserted into the tree.
In my case, the code was as follows (comments added):
// get the element to position the HTML relative to
let element = document.getElementById("quarto-header");
// create the string to be parsed as HTML
let skiplink = '<a id="skiplink" class="visually-hidden-focusable" href="#title-block-header">Skip to main content</a>';
// insert the HTML before (in this case) the chosen element
.insertAdjacentHTML('beforebegin', skiplink); element
The .visually-hidden-focusable
class is part of Bootstrap 5, which Quarto uses under the hood. To learn more about .visually-hidden-focusable
and other accessibility-related features, see the Bootstrap Accessibility documentation.
Adapted from answer to Inserting HTML elements with JavaScript by svnm.