Skip to content

Instantly share code, notes, and snippets.

@bmartel
Created April 7, 2022 16:46
Show Gist options
  • Save bmartel/b8ba610253ee0c085a030991f0eb57cc to your computer and use it in GitHub Desktop.
Save bmartel/b8ba610253ee0c085a030991f0eb57cc to your computer and use it in GitHub Desktop.
Simple snippet for creating vanilla web components.
export const define = (
name: string,
ElCtor: CustomElementConstructor,
options?: ElementDefinitionOptions
): void => {
if (typeof window !== 'undefined') {
customElements.define(name, ElCtor, options)
}
}
if (typeof window === 'undefined') {
global.HTMLElement = function () {
//
} as any
}
export abstract class CustomElement extends HTMLElement {
public mountPoint: HTMLElement | null = null
public shadowRoot: ShadowRoot | null = null
protected shouldUpdate(_previous: any, _next: any): boolean {
return true
}
protected createMountPoint(): void {
this.mountPoint = document.createElement('div')
this.mountPoint.innerHTML = this.render()
this.shadowRoot = this.attachShadow({ mode: 'open' })
this.shadowRoot.appendChild(this.mountPoint)
}
protected destroyMountPoint(): void {
if (this.mountPoint) {
this.shadowRoot?.removeChild(this.mountPoint)
}
this.mountPoint = null
this.shadowRoot = null
}
protected async connect(): Promise<void> {
return
}
protected async connectedCallback(): Promise<void> {
await this.connect()
this.createMountPoint()
}
protected disconnect(): void {
return
}
protected disconnectedCallback(): void {
this.disconnect()
this.destroyMountPoint()
}
protected forceRender(): void {
this.mountPoint.innerHTML = this.render()
}
protected maybeRender(oldValue: any, newValue: any): void {
if (this.mountPoint && this.shouldUpdate(oldValue, newValue)) {
this.forceRender()
}
}
protected attributeChangedCallback(_name: string, oldValue: any, newValue: any): void {
this.maybeRender(oldValue, newValue)
}
abstract render(): string
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment