I have a family of HTML websites that all have similar design, but different titles, description and SEO keywords
For each and every site I need to add
<meta name="title" content="Title siteA">
<meta name="description" content="Description siteA">
<!-- and many more tags -->
I want a single location to update all sites meta data
Traditionally you would solve this with an SSR (Server Side Rendering) solution.
But my source is bare HTML, not created by any Server script.
and SSR can not read any Client Side settings, like URL Parameters, sessionStorage or localStorage.
a CSR (Client Side Rendering) Web Component : <site-head>
Web Components can create DOM elements.
Then one Web Component can create all <meta>
DOM elements.
⚠️ and after it has done the work, remove itself from the DOM
<head>
<site-head site="A">Description of this site</site-head>
</head>
The JavaScript required is very simple:
customElements.define("site-head", class extends HTMLElement {
connectedCallback() {
// append all <meta> tags to document.head
this.remove();
}
})
It is magic, <site-head>
was never in the <head>
If you do not remove the <site-head>
element with this.remove()
,
addendum from comments:
you will notice some (maybe) unexpected behaviour:
Although the Web Component is defined in the <head> of the HTML document.
The element closes the head and then starts the body. This means that any following element that could live in either the head of body will end up in the body! (the </head> will be ignored, and the <body> will be merged with the body implicitly opened by the site-head).
connectedCallback(){
console.log( this.parentNode );
}
will log <body>
not <head>
This is because <site-head>
is not a valid HEAD Element: meta, link, title, style, script, noscript, base
The Web Component is correctly executed after being placed in the <body>
by the Browser.
This is very annoying when you create a CSR <css-grid>
that applies a CSS grid to the <body>
tag, because <site-head>
now is a grid element, until it is removed.
And maybe you are doing async stuff in <site-head>
, so the this.remove()
executes late.
Vanish! Go away! Get out of that <body>
!
Because Web Components trigger the disconnectedCallback
when removed from the DOM.
The Web Component can immediately be removed from the <body>
in the connectedCallback
⚠️ The element and all its attributes and content is still available in the disconnectedCallback
⚠️ But the element is no longer in the DOM
customElements.define("site-head", class extends HTMLElement {
connectedCallback() {
this.remove();
}
disconnectedCallback() {
console.log( this ); // <site-head>
console.log( this.parentNode ); // null
// append all <meta> tags to document.head
}
})
All <site-head>
Web Component code required
Here is code to get you started
You can get inspiration from:
- Everything you can do in
<head>
: https://htmlhead.dev/#elements - Vue Component setting
<head>
content : https://github.com/ktquez/vue-head
Top comments (2)
Small note: the element is not moved to the body, it closes the head and then starts the body. This means that any following element that could live in either the head of body will end up in the body! (the
</head>
will be ignored, and the<body>
will be merged with the body implicitly opened by thesite-head
).Good description, I added it to the text, tnx