Skip to main content

shadow

Shadow is a dependency-free base class inheriting from HTMLElement - makes Web Components and ShadowRoot simple and fun.

Quick Start

Compile the my_example.ts by running:

# Add a tsconfig.json with DOM types to enable type checking
deno bundle --no-check example/my_example.ts > example/my_example.js

Serve the index.html:

deno run --allow-net --allow-read https://deno.land/std/http/file_server.ts example/

Example

import {
  css,
  customElement,
  html,
  property,
  Shadow,
} from "https://deno.land/x/shadow/mod.ts"

@customElement()
export class MyExample extends Shadow {
  @property()
  h1Content = 0
  @property()
  pContent = "some text"

  clickHandler(e: MouseEvent) {
    return this.h1Content++
  }

  static styles = css`
    h1 {
      color: blue;
    }
    #myButton {
      color: green;
    }
  `

  render() {
    return html`
      <h1>${this.h1Content}</h1>
      <p>${this.pContent}</p>
      <button @id="myButton click=${this.clickHandler}">Count</button>
    `
  }
}

API

function html(strings: TemplateStringsArray, …expressions: AllowedExpressions[]): Html

The html tag function parses html strings containing the special marker @ and various AllowedExpressions. Putting an @ before id or class in your html code has two effects:

  1. The element(s) matching the selector will be queried and added to the this.dom object. All matching class elements or one id element. E.g. to the button element of <div><button @id="myButton"></button></div> can be referred with this.dom.id["myButton"].
  2. This allows you to add EventListeners, e.g. click=${this.clickHandler}, which will be added with the native addEventListener method under the hood. You don’t need arrow functions because because we use bind(this).

function css(strings: TemplateStringsArray, …values: (string | HTMLTemplateElement)[])

The css tag function parses css strings which can contain expressions with the type string or HTMLTemplateElements (containing a script element).

function customElement(tagName)

The customElement decorator takes the tag name of the custom element and registers the custom element. If no tag name is passed, the class name is used instead through converting it from CamelCase to dash-case. The same tag name is assigned to the static is property.

function property({reflect, wait, assert}: PropertyOptions)

The property decorator takes an optional object as argument with three optional properties:

  • Setting reflect to false would stop the element’s attribute from synchronising.
  • If you plan to use properties instead of attributes as data input, setting wait to true would reduce the amount of renderings from 2 to 1 (you can just ignore it).
  • The assert boolean checks if the input has a truthy value.

class Shadow extends HTMLElement

This class is the reason why you are here.

constructor(init: ShadowRootInit)

readonly argsFromPropertyDecorator?: Required

connected: boolean

shadowRoot: ShadowRoot

dom: Dom

In the dom object are the child elements stored which match the selectors you marked with the @ sign in the html string.

static styles: HTMLTemplateElement[]

The return type of the function css, which is an array of HTMLTemplateElements containing a script element, is assigned to this

static property.

static is: string | null

The decorator customElement - if used - sets this static property to the custom element’s tag name automatically.

connectedCallback()

A native custom elements’ lifecycle callback. If you want to modify this callback you must call super.connectedCallback() inside of it.

attributeChangedCallback(name: string, oldValue: Attribute, newValue: Attribute)

A native custom elements’ lifecycle callback: It will cause reflecting of properties to attributes

init(properties: PropertyAndOptions[]): void

Assigns the accessors to the element’s properties and initializes the lifecycle while considering the conditions coming from the property decorator. You will never need to use this method if you use the property decorator.

update(name: string, newValue: Attribute, isRendering): void

Reflects properties to attributes and calls actuallyRender if the optional boolean isRendering is true (default: true).

dispatchCustomEvent(eventName: string, {bubbles, composed, detail})

Dispatch a CustomEvent which bubbles as default through the whole DOM.

isInEventPath(event: Event, selector: string): boolean

Checks if an element matching the selector is in the event’s composedPath(). It takes an event and a selector as arguments where the custom element’s tagName is the default selector.

changeCss(styles: Record, selector?: string): void

Takes a JavaScript style object and an optional selector (default is the custom element itself) and adds or changes specific inline styles to the element matching the selector without altering other style values. CSS custom properties (variables) are allowed.

getSlotElements(): HTMLElement[]

Returns an array of the slot elements of the custom element.

render(): Html

Is called by the method actuallyRender which renders the custom element. It must return the return type of the function html.

firstUpdated(): void

A modifiable lifecycle callback which is called after the first update which includes rendering.

updated(): void

A modifiable lifecycle callback which is called after each update which includes rendering.