I have about 100 lines of boilerplate HTML that every file on my site begins with. It contains the following elements:
<!-- START OF BOILERPLATE TEXT -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta ...>
<link href="..." rel="stylesheet">
<script src="..."></script>
<title>MY_TITLE</title>
</head>
<body>
<div> Page banner ... </div>
<hr>
<!-- END OF BOILERPLATE TEXT -->
I’d like to minimize the actual amount of boilerplate code needed for each page, and I’ve come up with the following solution:
<!-- Line 1 of actual code will load external script:
<script src="/test/scripts/boot.js"></script>
For this demo I'm inlining it. -->
<script>
async function boot(title) {
// Will insert header boilerplate in document.documentElement.
// Actual code will fetch boilerplate code from server.
const my_demo = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- ****************** page-specific <head> stuff ***************** -->
<title>${title}</title>
<!-- ****************** end page-specific stuff ***************** -->
</head>
<body>
<h1>Banner injected by boot.js</h1>
<hr> <!-- end of page banner -->
<!-- ****************** begin page content ***************** -->
`;
try {
document.documentElement.innerHTML = my_demo;
} catch (my_error) {
document.write('Error: ', my_error);
}
}
</script>
<!-- Line 2 of actual code will invoke boot() -->
<script>boot("Test Title")</script>
<!-- Now we begin adding our body html -->
<p>
This is the actual content of the page. It should appear under the injected H1 and HR.
</p>
Here is the way I want it to look:
The boot() script appears to correctly insert my <head>
and banner html, but my "actual content" doesn’t appear underneath. According to the Safari debugger, there was a </body>
tag inserted after the last line inserted by boot(). How can I prevent that?
2
Answers
Brother,
document.documentElement.innerHTML
rewrites the entire html element including the<head>
and<body>
.If you want to keep the existing content you can use
insertAdjacentHTML
!here is the correct code:
When you insert text into the DOM (your .innerHTML = my_demo), the browser will close off any elements in order to keep the DOM as correct as it can. Which is why you are seeing a
</body>
that you did not put there.Here is an example of doing what I think you are asking, by surrounding your real HTML body in an element (
<main>
in my example) with an id unique enough not to be found in your HTML otherwise. "MainHtmlToBeAppended" in my example.Then you can retrieve your HTML and include with your my_demo string when setting .innerHTML.
I use "defer" in the script tag to ensure the DOM is loaded before trying to access it.
Note that I moved the boot("Test Title") invocation into the .js file, but you could leave it in your html file if you prefer. It just keeps the "extra" content in your .html file to a minimal single
<script>
line.