Building Web Components 101 - Part 1
Tags: javascript, webdev, webcomponents, fastdesign
Published: 2022-09-10 05:50:01

> Web Components is a suite of different technologies allowing you to create reusable custom elements — with their functionality encapsulated away from the rest of your code — and utilize them in your web apps. ~ [MDN](https://developer.mozilla.org/en-US/docs/Web/Web_Components)

Let's clarify what that really means. Currently, there are many ways to build re-usable components such as using React, Vue, Angular, etc... However, if a component is built with React, it does not work in Angular, though there are some libraries to make it work. However, natively React components do not work in Angular and vice versa. Web Components addresses this challenge. 

Since Web Component is an HTML standard, it can be understood or rendered by the browser without any libraries. 

To better understand this, let's look at a standard HTML tag such as 

```html
<h1>Cool Title</h1>
```
For libraries and frameworks to render `<h1>`, as developers we do not need to load any scripts. We expect the library and framework to simply build the page and the browser to simply render it.  

In **React**, we could use an `<h1>` tag like below:

```jsx
import * as React from 'react';
import './style.css';

export default function App() {
  return <h1>Cool Title</h1>;
}
```

In **Angular**, we could use an `<h1>` tag like below:
```js
import { Component, Input } from '@angular/core';

@Component({
  selector: 'hello',
  template: `<h1>Cool Title</h1>`,
  styles: [`h1 { font-family: Lato; }`],
})
export class HelloComponent {
  @Input() name: string;
}

```

And a browser will render it because it understands HTML standard `<h1>` tag. 

What if we were able to build our own tags such as `<tebin-h1>`, `<fancy-h1>` tags, etc...and tell the browser to render them exactly as it would render `<h1>`? 

**Using Web Components, we can build custom tags or elements and then inform the browser to render them. These custom tags are called Web Components.** 

Web Components are re-usable. The same way an `<h1>` tag is re-usable, a custom web component is also re-usable because it is natively supported by the browser. 

Browser compatibility of Web Components and its different feature compatibility can be found [here](https://developer.mozilla.org/en-US/docs/Web/Web_Components#browser_compatibility) 


Since Web Components are supported natively by browsers, they can be used in any libraries and frameworks either directly or with configurations. [https://custom-elements-everywhere.com/](https://custom-elements-everywhere.com/) is a great site to check custom elements support status by different libraries and frameworks.


## How to build Web Components

Since Web Components are natively supported by browsers, we technically can write vanilla HTML, JavaScript, and CSS to build our custom web component. Below is a complete `index.html` page to create a custom tag that I named `<tebin-h1>`. This custom `<h1>` tag has a brown colour by default. 
 
```html
<html lang="en">

<head>
    <title>Web Component 101 - Part 1</title>
</head>

<body>
    <h1>Quotes</h1>

    <tebin-h1>Albert Einstein</tebin-h1>
    <p>Life is like riding a bicycle. To keep your balance, you must keep moving.</p>

    <tebin-h1>Pablo Picasso</tebin-h1>
    <p>Everything you can imagine is real.</p>
</body>

<script>
    // Create a class for the element
    class CustomTebinH1 extends HTMLElement {
        constructor() {
            // Always call super first in constructor
            super();

            // Create a style tag
            const style = document.createElement('style');
            style.textContent = 'h1 {color: brown}';

            // Create an h1 tag
            const h1 = document.createElement('h1');
            h1.textContent = this.textContent;
            this.textContent = '';

            // Create a shadow root
            const shadow = this.attachShadow({ mode: 'open' });

            // Append it to the shadow root
            shadow.append(style, h1);
        }
    }

    // Define the new element
    customElements.define('tebin-h1', CustomTebinH1);
</script>

</html>
```
Result:

![A screenshot to show how the HTML above is rendered. It shows two quotes by Albert Einstein and Pablo Picasso](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pl562xj5mwg28e5zgmyd.png)


Let's break it down. 
1. Usage: `<tebin-h1></tebin-h1>` we use custom elements or web components the same way we use standard HTML elements. 
2. Build: There are two steps: 
  
**Step 1:** Create a JavaScript class for the custom component functionality.
**Step 2:** Define or register the custom element so that the browser understands how to render the custom element. This is done using `customElements.define('tebin-h1', CustomTebinH1);`

Obviously, this is a very simple custom element. When we add more functionalities, our class becomes more complex. As engineers, we like to define patterns or follow best practices to build software. This is where abstraction layers become very useful and saves a lot of time. 

There are already great libraries that provide abstractions and good patterns to speed up development some of these libraries are [FAST](https://www.fast.design/docs/fast-element/getting-started/), [Lit](https://lit.dev/), [Custom Element Builder](https://tmorin.github.io/ceb/index.html), etc...

In future posts, I will dive deep into FAST and how it helps to build custom elements FASTer.