Skip to content

Custom Elements with a safer, more expressive interface.

Notifications You must be signed in to change notification settings

jamesdiacono/ui.js

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 

Repository files navigation

ui.js

ui.js is a JavaScript library that gives you the power of Custom Elements without making you use JavaScript classes, properties, or this.

Instead, ui.js provides an interface based on two of JavaScript's best parts: modules and functions. You can use ui.js to build web applications of any size.

ui.js is in the Public Domain.

The Problem with Custom Elements

The biggest problem with Custom Elements is the use of a global, name-based registry. To instantiate a Custom Element, you must reference it by name. That is fine for small websites, but for large web applications it is a recipe for disaster because the dependency graph is not explicit.

The Custom Elements specification predates the addition of modules to JavaScript. Modules provide a clear, statically-analyzable dependency graph, essential in any large application. ui makes functions that can be exported from modules.

The other problem with Custom Elements is that it mandates the use of JavaScript classes and this, both of which are dangerous and unnecessary parts of the language. There is also no way to pass parameters when creating a Custom Element, resulting in heavy use of properties.

ui takes a create function that provides a closure where all of the element's state can live, held in private variables. Variables are safer to use than properties because they are actually private, and there is no weirdness arising from the prototype chain. Douglas Crockford coined the term Class Free to describe this pattern.

Usage Examples

In the following trivial example, we make a colorful function that makes colorful elements. We then make red_element, populate it with some text, and add it to the page.

import ui from "./ui.js";

const colorful = ui("colorful-ui", function create(element, params) {
    element.style.color = params.color;
});
const red_element = colorful({color: "red"});
red_element.textContent = "I am red.";
document.body.append(red_element);

The state of the DOM is now:

<body>
    <colorful-ui style="color: red;">I am red</colorful-ui>
</body>

Now for a more realistic example. The module, blink.js, demonstrates the use of the Shadow DOM, connect/disconnect callbacks, and public methods.

blink.js exports a function that makes blinking elements. The interval property of the params object controls the frequency of the blinking. The blinking begins as soon as the element is connected to the page.

The timer is stopped by clearInterval when the blinking element is removed from the page, preventing a memory leak and wasted CPU cycles.

The element's change_interval method can be called externally to modify the interval at any time.

// blink.js

import ui from "./ui.js";

export default ui("blink-ui", function create(element, params) {
    let {interval} = params;
    let timer;
    let shadow = element.attachShadow({mode: "closed"});
    shadow.append(document.createElement("slot"));

    function toggle_visibility() {
        element.style.visibility = (
            element.style.visibility === "hidden"
            ? "visible"
            : "hidden"
        );
    }

    function connect() {
        timer = setInterval(toggle_visibility, interval);
    }

    function disconnect() {
        clearInterval(timer);
    }

    function change_interval(new_interval) {
        interval = new_interval;
        if (element.isConnected) {
            disconnect();
            connect();
        }
    }

    element.change_interval = change_interval;
    return {connect, disconnect};
});

Elsewhere in the application, blink is imported, and a blinking element created. The element is populated and added to the page.

// my_app.js

import blink from "./blink.js";

const blink_element = blink({interval: 300});
blink_element.textContent = "Look at me!";
document.body.append(blink_element);

// Some time later...

blink_element.change_interval(100); // strobe!

The state of the DOM is now something like:

<body>
    <blink-ui style="visibility: hidden;">
        <slot>Look at me!</slot>
    </blink-ui>
</body>

The Functions

ui(tag, create) → make_element(params) → Element

The ui function returns a function that makes elements. The tag is the name of the element, and must be a valid custom element name. The create function initializes a newly created element, and is described below.

create(element, params) → {connect, disconnect}

The create function takes two parameters, element and params. The element is a brand new element with tag name tag. The params is whatever was passed to make_element.

The create function may return an object with connect and disconnect callbacks.

About

Custom Elements with a safer, more expressive interface.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published