The <site-head> Web Component you never see in F12 Dev Tools
Tags: webcomponents, webdev, javascript
Published: 2021-04-30 09:24:40

---
title: The <site-head> Web Component you never see in F12 Dev Tools
published: true
description: 
tags: webcomponent, webcomponents, webdev, javascript
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sh6zhnn12cz6lhjjxwd2.png
---

I have a family of HTML websites that all have similar design, but different titles, description and SEO keywords

{% jsfiddle https://jsfiddle.net/WebComponents/mxbf3c0v result %}

For each and every site I need to add 

```html
<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.

<hr>

## a **CSR** (Client Side Rendering) Web Component : &lt;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**


```html
  <head>
    <site-head site="A">Description of this site</site-head>
  </head>  
```

The JavaScript required is very simple:

```js
customElements.define("site-head", class extends HTMLElement {
  connectedCallback() {
    // append all <meta> tags to document.head
    this.remove();
  }
})
```

<hr>

## It is magic, ``<site-head>`` was never in the &lt;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 **&lt;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 &lt;/head> will be ignored, and the &lt;body> will be merged with the body implicitly opened by the site-head).


```js
connectedCallback(){
    console.log( this.parentNode );
}
```

will log ``<body>`` **not** ``<head>``
<br>
<br>
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.

<hr>

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.

<hr>

## 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

 ```js
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
  }
})
```

<hr>

## 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

{% jsfiddle https://jsfiddle.net/WebComponents/mxbf3c0v js,html %}

<hr>

## Challenge

Now it is your turn to create **any** gameboard with a CSR ``<css-grid>`` Web Component:

```html
<css-grid background="khaki" 
          files="ABCDEFGH" 
          ranks="12345678" 
          gap="0" 
          colors="#f0e9c5/#b58863" 
          labels="center"></css-grid>
```

<hr>

{% jsfiddle https://jsfiddle.net/WebComponents/62f1eLay result,html,js %}