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>

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"

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
element.insertAdjacentHTML('beforebegin', skiplink);

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.