# Element Types

[Web Components](..) ⟩ [Custom Elements]() ⟩

{% tabs %}
{% tab title="📘 手冊" %}
* MDN ⟩ CSS ⟩ [is](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes#attr-is) attribute
* Google ⟩ [Extending native HTML elements](https://developers.google.com/web/fundamentals/web-components/customelements#extendhtml)
{% endtab %}

{% tab title="Second Tab" %}

{% endtab %}
{% endtabs %}

* **autonomous** custom elements:\
  “all-new” elements, extending the abstract `HTMLElement` class.&#x20;
* **customized** built-in elements:\
  extending built-in elements (such as `<p>`, `<a>`, `<br>`)

### Autonomous

:floppy\_disk: [replit.com](https://replit.com/@pegasusroe/web-component#script.js)

{% tabs %}
{% tab title="JS" %}
```javascript
// ⭐️ 1. custom web component
class MyComponent extends HTMLElement {

    // constructor
    constructor() {

        // tell HTMLElement to initialize itself.
        super();

        // get `width`, `height` attributes
        const height = this.getAttribute('height') || '100px';
        const width = this.getAttribute('width') || '100px';

        // create <template> element
        const template = document.createElement('template');
        template.innerHTML = MyComponent.template(height, width);

        // add component to UI
        this.appendChild(document.importNode(template.content, true));
    }

    // template HTML
    static template(height, width) { 
        return ` 
            <style> 
                .placeholder { 
                    background-color: pink; 
                    width: ${height}; 
                    height: ${width}; 
                }
            </style>

            <div class='placeholder'>Placeholder</div>
        `;
    }
} 

// ⭐️ 2. custom tag <my-component>
// ⭐️⭐️ custom element names must contain a "hyphen".
customElements.define('my-component', MyComponent);
```
{% endtab %}

{% tab title="HTML" %}
```markup
<!-- web component -->
<my-component></my-component>
```
{% endtab %}

{% tab title="codepen" %}
{% embed url="https://codepen.io/lochiwei/pen/PojNgmB" %}
{% endtab %}

{% tab title="📗 參考" %}
* [Case Styles: Camel, Pascal, Snake, and Kebab Case](https://betterprogramming.pub/string-case-styles-camel-pascal-snake-and-kebab-case-981407998841)\
  `camelCase`, `PascalCase`, `snake_case`, `kebab-case`&#x20;
{% endtab %}
{% endtabs %}

### Customized Built-in Elments

* 💾 [fancy-button](https://replit.com/@pegasusroe/FancyButton#script.js), [bigger-image](https://replit.com/@pegasusroe/BiggerImage#script.js)

{% tabs %}
{% tab title="JS" %}
```javascript
// 1. extend built-in element 
class FancyButton extends HTMLButtonElement { 
    constructor(){...} 
}

// 2. register new tag
customElements.define('fancy-button', FancyButton, {extends: 'button'});

// 3. create with `document.createElement()`
let button = document.createElement('button', {is: 'fancy-button'});
button.textContent = 'Fancy button!';
button.disabled = true;
document.body.appendChild(button);

// 4. create with `new`
let button = new FancyButton();
button.textContent = 'Fancy button!';
button.disabled = true;
```
{% endtab %}

{% tab title="HTML" %}
```markup
<!-- 3. use `is` attribute -->
<p is="my-paragraph">some text</p>
```
{% endtab %}
{% endtabs %}

{% hint style="info" %}
The required third parameter **{extends: p}** tells the browser **which tag** you're extending. This is necessary because many HTML tags **share** the **same DOM interface**.&#x20;

* <**section**>, <**address**>, and <**em**> (among others) all share **HTMLElement**.
* both <**q**> and <**blockquote**> share **HTMLQuoteElement**, etc..&#x20;

Specifying **{extends: 'blockquote'}** lets the browser know you're creating a souped-up <**blockquote**> instead of a <**q**>.\
📘 Google ⟩ [Extending native HTML elements](https://developers.google.com/web/fundamentals/web-components/customelements#extendhtml)
{% endhint %}

