Last active
January 20, 2025 03:56
-
-
Save mantyr/a5ab8812748029134519a519b2d4e588 to your computer and use it in GitHub Desktop.
Shadow DOM and base component for web components
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| export class ShadowDomBaseComponent extends HTMLElement { | |
| static shadowMode = 'open'; | |
| static templateURL = ''; | |
| static templateCache = null; | |
| constructor() { | |
| super(); | |
| this.isCustomTag = true; | |
| const shadowMode = this.constructor.shadowMode || 'open'; | |
| this.attachShadow({ mode: shadowMode }); | |
| } | |
| connectedCallback() { | |
| this.shadowRoot.innerHTML = ''; | |
| this.shadowRoot.appendChild(this.constructor.templateCache.cloneNode(true)); | |
| } | |
| static async init() { | |
| try { | |
| const defaultTemplateURL = new URL('component.tmpl', import.meta.url); | |
| const address = this.constructor.templateURL || defaultTemplateURL.href; | |
| const response = await fetch(address); | |
| if (!response.ok) throw new Error(`Failed to fetch template from ${address}`); | |
| const html = await response.text(); | |
| const parser = new DOMParser(); | |
| const doc = parser.parseFromString(html, 'text/html'); | |
| this.templateCache = doc.body.firstChild; | |
| } catch (error) { | |
| console.error(`Error preloading template: ${error}`); | |
| throw error; | |
| } | |
| } | |
| static async define(tagName) { | |
| customElements.define(tagName, this); | |
| const customElements = document.querySelectorAll(tagName); | |
| customElements.forEach(element => { | |
| if (!element.isCustomTag) { | |
| const newComponent = new this(); | |
| element.replaceWith(newComponent); | |
| } | |
| }); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import {ShadowDomBaseComponent} from "base/shadow-dom-base-component.js" | |
| export class AComponent extends ShadowDomBaseComponent { | |
| static shadowMode = 'open'; | |
| constructor() { | |
| super(); | |
| } | |
| } | |
| await AComponent.init(); | |
| await AComponent.define("a-component"); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import {ShadowDomBaseComponent} from "base/shadow-dom-base-component.js" | |
| export class BComponent extends ShadowDomBaseComponent { | |
| static shadowMode = 'close'; | |
| static templateURL = "https://example.com/component-b/template.html"; | |
| constructor() { | |
| super(); | |
| } | |
| connectedCallback() { | |
| super.connectedCallback(); | |
| this._attachEvents(); | |
| this._renderData(); | |
| } | |
| _renderData() { | |
| const dataElement = this.shadowRoot.querySelector('.data-container'); | |
| if (dataElement) { | |
| dataElement.textContent = this.getAttribute('data'); | |
| } | |
| } | |
| _attachEvents() { | |
| const button = this.shadowRoot.querySelector('button'); | |
| if (button) { | |
| button.addEventListener('click', this._onButtonClick.bind(this)); | |
| } | |
| } | |
| _onButtonClick() { | |
| console.log('Button clicked!'); | |
| alert('Button clicked in BComponent!'); | |
| } | |
| } | |
| await BComponent.init(); | |
| await BComponent.define("b-component"); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!doctype html> | |
| <html> | |
| <head> | |
| <script type="module" src="component-b/component.js"></script> | |
| </head> | |
| <body> | |
| <b-component data="example text"></b-component> | |
| </body> | |
| </html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!-- https://example.com/component-b/template.html --> | |
| <template> | |
| <div> | |
| <h1>BComponent</h1> | |
| <div class="data-container"></div> | |
| <button>Click me</button> | |
| </div> | |
| </template> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment