element-js

April 17, 2026 · View on GitHub

Introduction

element-js is a collection of base classes for Custom Elements with a beautiful API for building fast and lightweight Web Components that work with any framework or without a framework at all - because they are just html and vanilla javascript.

element-js aims to combine the best concepts of current and popular frontend frameworks and web-standard into a single toolset that will never be outdated because it is just html and javascript.

Why Custom elements

By using web-standards, developers only need to learn the standard web API once rather than custom framework APIs over and over again.

While popular frontend frameworks come and go, web components and custom elements will always be part of the web standard API. And since they conform to the standard web API, they work in any major frontend framework.

Custom elements provide a component model for the web and enable developers to define their own elements. With custom elements you get a mechanism to associate an ES class with a custom element name which then can be used in HTML alongside any other element. Inside the class you can define the public API for the custom element.

Why element-js

Using Custom Clements directly can be quite cumbersome because the underlying API is very low level. To prevent writing a lot of boilerplate element-js provides extra APIs that enable writing components fast with very little code.

On top of that it also brings some nice features like

  • async update/render cycle
  • automatic mapping of attributes to properties
  • objects, arrays, numbers and booleans as attributes (instead of just strings)
  • reflecting properties to attributes
  • abstraction for writing templates
  • mechanism for loading styles per element
  • loading global styles into Shadow Dom

And the best thing? There is no magic! No Framework. No compiler. You only need to extend from an element-js element instead of the standard HTMLElement.

Browser Support

element-js Elements are natively supported in all modern Browsers including Chrome, Edge, Firefox, and Safari.

ChromeEdgeFirefoxSafari
v. 60+v. 79+v. 63+v. 10.1+

If you need to support older Browsers like IE 11 or Edge 16-18 you will have to load one or two polyfills for Custom Elements to work seamlessly. element-js does not bring or load any polyfills on its own. You will have to bundle or load them yourself. For more information see Bundling/Publishing.

element-js comes unbundled, unminified and uses a few Babel plugins. Browser support can also be limited for any of the Babel plugin features, you will probably have to use a build step and run your code through something like Babel. For a list of Babel plugins that are used, see ES6 Classes. For more information on bundling and publishing your elements see Bundling/Publishing.

Getting Started

Element Core Concepts

Features

Getting started

npm install @webtides/element-js

You can install element-js into an existing project or create a new app from scratch.

First Element

To define a custom element, create a class that extends element-js and pass the class with a name to the defineElement helper function.

By specification, a custom element's name can only have lower case letters and must contain a dash.

Here is an example of what a element-js element looks like:

import { BaseElement, defineElement } from '@webtides/element-js';

class ExampleElement extends BaseElement {
    // normal public properties
    greeting = 'Hello';
    name = 'John';

    // lifecycle hook
    connected() {
        this.greet();
    }                                                                

    // reactive attributes/properties
    properties() {
        return {
            familyName: 'Doe'
        };
    }

    // watchers for property changes
    watch() {
        return {
            familyName: (newValue, oldValue) => {
                console.log('familyName changed', newValue, oldValue);
            }
        };
    }

    // computed property
    get computedMsg() {
        return `${this.greeting} ${this.name} ${this.familyName}`;
    }

    // method
    greet() {
        alert('greeting: ' + this.computedMsg);
    }
}

defineElement('example-element', ExampleElement);

You don't need to fully understand everything just now. We'll explain each part in detail later on.

When the JS class is built, this element can be imported and used in HTML just like any other element tag.


<example-element family-name="Smith"></example-element>
<script type="module" src="./example-element.js">

When rendered in the browser, it will log to the console: Hello John Smith

Guides/Tooling

Testing

Overview

Feature tests

Unit tests

@webtides/element-library

@webtides/layouts