Web Components using UnknownHTMLElements for better semantic HTML
Tags: webcomponents, webdev, javascript
Published: 2021-04-24 16:25:29

---
title: Web Components using UnknownHTMLElements for better semantic HTML
published: true
description: Using Web Components to draw Pie Charts with semantic HTML
tags: WebComponents,WebDev,WebComponent,JavaScript
cover_image: https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/63359009-cca5-43fe-bc88-c928d5dbac4d/01-html-baby-opt.jpg
---

### 🥧 TL;DR; 

* ``UnknownHTMLElement`` elements **can** be used as Web Component building blocks
* The ``<pie-chart>`` and ``<progress-circle>`` Web Components, used in this post are available on https://pie-meister.github.io

<hr>

## ``<slice>`` is an **UnknownHTMLElement**

In [my previous post](https://dev.to/dannyengelman/what-web-technologies-are-required-to-draw-a-pie-chart-in-2021-spoiler-alert-a-standard-web-component-will-do-1j56) 
I explained how to build a _vanilla JavaScript_ ``<pie-chart>`` Web Component.

With **semantic HTML** creating a Pie Chart:

```html
<pie-chart>
  <slice size="90" stroke="green">HTML</slice>
  <slice size="1"  stroke="red">JavaScript</slice>
  <slice size="9"  stroke="blue">CSS</slice>
</pie-chart>
```

![](https://i.imgur.com/MWUIQVe.png)

Experienced Web Developers commented ``<slice>`` is **not a valid HTML Element**. 

```js
document.querySelector("slice").constructor.name === "HTMLUnknownElement"
```

Neither is it a valid **Custom Element**, because those always require **at least one hyphen** in the tagname.

That hyphen restriction is to prevent conflicts with any HTML tags the WHATWG might add _**in the future**_.

Custom Element tag names:
* have to **start with** a lowercase ASCII character
* **can't have uppercase** characters anywhere
* must contain at least one **hyphen** - character
* UTF-8 characters, **emojis** are allowed: ``<a-🥧-chart>``
* cannot be self closing: ``<pie-chart/>``

<hr>

## What is the value of using ``<slice>`` ?

### ``<pie-chart>`` must be a **unique** Custom Element (extended from HTMLElement)

* Scoped registries have been [on the agenda for 4 years now](https://github.com/WICG/webcomponents/issues/716). 
For now **all** Custom Elements go into the same **global _customElementsRegistry_**

* That means ``customElements.define("pie-chart")`` can only be called **once**. 

* If an element **with the same tag name** was already created, 
my ``<pie-chart>`` element will throw an error:

  ![](https://i.imgur.com/ICumcGD.png)


* For a good UX (User eXperience) **and** DX (Developer eXperience) 
my ``<pie-chart>`` Web Component should test if it can be defined:

```js
if (customElements.get("pie-chart")) {
    // warn the user "my" Web Component doesn't work; another definition exists
    // warn the developer another Web Component with the same name exists
} else {
    customElements.define("pie-chart", ... )
}
```

<hr>

## To ``<slice>`` or to ``<pie-slice>``, that is the question

### ``<slice>`` has less restrictions

* A **duplicate** ``<slice>`` can only be created by the WHATWG **adding** ``<slice>`` as standard HTML tag.

* Till then. I know **with 100% certainty** there will not be a naming conflict. 

* Because **no 3rd party Developer** can create a valid ``<slice>`` element:
![](https://i.imgur.com/2s9uAII.png)

* Had I used a ``<pie-slice>`` **Custom Element**, 
it would have been an additional point of failure. 
I would have to add extra code to check if ``<pie-slice>`` was defined **by another developer**; like required for ``<pie-chart>``

### ``<pie-slice>`` versus ``<slice>``

* ``<pie-slice>`` can have all the **Web Components goodies**: ``observedAttributes`` , ``attributeChangedCallback`` etc.

* ``<slice>`` will always be an UnknownHTMLElement. 
``observedAttributes``-like behaviour can only be created by adding a [MutationObserver](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) (_yes, works on Unknown Elements_)
You then get an extra bonus; because a MutationObserver can observe **text Node** changes. 
A **Custom Element** can not monitor the ``innerHTML`` label.

<hr>

## (ab)using **existing** HTML tags

We can test the "_WHATWG created a new HTML tag_" scenario.

``<progress>`` is an **existing** HTML tag 

> And for those who don't know. 
Many standard HTML elements, ``<input>`` , ``<video>``, **_are_ Web Components** 
Browsers have different implementations; 
check out [the ``<progress>`` documentation page](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/progress) in Chrome, Firefox or Safari

Similar to ``<pie-chart>`` (and using the same Base Class, available on https://pie-meister.github.io)

This chart (modelled after a Google Analytics chart):

![](https://i.imgur.com/K8mAUHM.png)

is created by the ``<progress-circle>`` Web Component, from **semantic HTML**:

```html
<progress-circle>
  <progress value="75%" stroke="green">SEO</progress>
  <progress value="60%" stroke="orange">Social</progress>
  <progress value="65%" stroke="teal" edge="black">Maps</progress>
  <progress value="50%" stroke="orangered">Traffic</progress>
</progress-circle>
```

* This Web Component uses shadowDOM to display the chart, the semantic HTML remains **invisible** in **lightDOM**

* Thus you do not see the ``<progress>`` default behaviour

* If you really, _really_ want a "NO JavaScript!" version, you have to change the HTML, CSS (and Web Component code) a bit to work with _something like_ this:  
```html
<progress max="100" value="75" stroke="green" label="SEO"></progress>
<progress max="100" value="60" stroke="orange" label="Social"></progress>
<progress max="100" value="65" stroke="teal" label="Maps"></progress>
<progress max="100" value="50" stroke="orangered" label="Traffic">Traffic</progress>
```

* again, the ``<progress>`` elements remains **invisible** in lightDOM

* the resulting chart is displayed **in shadowDOM**

* I only have to safeguard a duplicate naming conflict for the ``<progress-circle>`` Web Component.

* As long as you can keep the output in **invisible lightDOM**, 
you can (ab)use any **existing HTML tag** for other purposes.

<hr>

## [Pie-Meister.github.io](https://Pie-Meister.github.io)

The ``<pie-chart>`` and ``<progress-circle>`` Web Components are available, as _unlicensed_ source code, on https://pie-meister.github.io

![](https://i.imgur.com/F6MSps6.png)

The code is an enhanced version of [my previous ``<pie-chart>`` post](https://dev.to/dannyengelman/what-web-technologies-are-required-to-draw-a-pie-chart-in-2021-spoiler-alert-a-standard-web-component-will-do-1j56)

* instead of a SVG ``<circle>`` Element, a ``<path>`` Element is used to draw slices. The ``<progress-circle>`` can **not** be created with ``<circle>`` elements.

* Uses shadowDOM 

* uses ::part shadowParts for optional global styling

* all in vanilla JavaScript, (way) **under 2 kB** GZipped

* a **starting point** for you own Web Components

<br>
<hr>
<br>

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