npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

thunderdom

v1.0.0

Published

ThunderDOM/e is a super lightweight frontend library with no build step. So simple you can learn in 5 minutes!

Downloads

15

Readme

ThunderDOM/e

Welcome to the ThunderDOM/e!

Now with added SSR Elements. Mmm.. delicious!

ThunderDOM/e is a super lightweight frontend library (Just 4kb un-minified) with no build step! ThunderDOM/e makes it easier to create web components without using huge bloated frameworks like Vue, Svelt, React or Angular or even libs like Solid or jQuery.

ThunderDOM/e components are based off of native web component architecture and use the shadow DOM which has been supported by all browsers since 2020. This simplifies the process of component creation and aligns the code with other languages using properties, getters, setters and events, reducing the cognitive load of the developer and the learning curve of the library.

It's so simple, a developer who knows javascript at the base level can learn in 5 minutes.

ThunderDOM/e should play nicely with HTMX hx- attributes but at this point that is untested so if you try it out, let me know!

ThunderDOM/e is comprised of just two classes and a few functions (as a lot of the functionality is currently built into all browsers), ThunderDOM/e just provides a clear and concise interface with which to interact with the web component system.

Client Rendered Components

This is an example of a client side ThunderDOMElement:

import * as TD from "../js/thunderDOM/thunderDOM.js";

class MyButton extends TD.ThunderDOMElement{

    //Variable declarations, getters, setters
    _clickCount = 0;
    get clickCount() {
        return this._clickCount;
    }
    set clickCount(value) {
        this._clickCount = value;
        const el = this.getEl("#foo");
        el.textContent = `Click Me (${value} clicks)`;
    }

    //DOM Element HTML, listener bindings and functions
    constructor() {
        super();
        this.component(()=>{
            return `<button id="foo">Click Me</button>`
        });
        //this.iCss(`#foo{background-color: green;}`); <-- You can also write inline CSS!
        this.css('/css/my-button.css');
        this.bind("#foo","click",(e)=>{this.clickCount++});
    }
}
customElements.define("my-button", MyButton);

Components may include as many HTML elements as you need but for this simple example we are just making a button.

This allows you to add a button to any page for client side js rendering:

<my-button></my-button>

This means you can use any backend or static html doc to output your components easily, here is an example in ASP .NET Core!

@for (var i = 0; i < 10; i++)
{
    <my-button id="button-@i"></my-button>
}

This will output a button with an id of "button-0" to "button-9". You can even use these id's for CSS selection of inner shadow dom elements allowing you to style your ThunderDOM components on a per element basis.

/*my-button.css*/
button {
   background-color: yellowgreen;
 }
/*If the shadow dom root (root component / parent) has id "button-1"*/
:host-context(#button-1) button {
   background-color: indigo;
 }

This CSS will style all 10 of the button's background color to "yellowgreen" via the component CSS and style just "button-1"'s background colour to "indigo". You can also write inline CSS with iCss("button{ background-color: yellowgreen; }") or use a lib like Tailwind.

this.shadowRoot returns the root element of the component we created when calling component()

But of course you might want to render your HTML on the server for SEO!

Server Rendered Components (SSR)

The latest update of ThunderDOM/e now supports binding events to server rendered components! There are a few differences from client side components to bare in mind when creating SSR components.

  1. No need to include the HTML markup in the javascript class
  2. SSR components cannot have their own local css like client side components

Component CSS support will improve in the future once more browsers adopt support for Declarative Shadow DOM

This is an example of a ThunderDOM SSR Element:

class MySsrButton extends TD.ThunderDOMElementSSR{

    //Variable declarations, getters, setters
    _clickCount = 0;
    get clickCount() {
        return this._clickCount;
    }
    set clickCount(value) {
        this._clickCount = value;
        //const el = this.getEl("#inner-foo"); <--you can still select children
        this.root.textContent = `Click Me (${value} clicks)`; //<--this.root to select root element 
    }
    //listener bindings and functions
    setBindings(){
        this.bind(this.root,"click",(e)=>{this.clickCount++});
    }
}

Its actually far simpler than the client side example. You can see that everything is the same minus a few lines of code and we are now extending ThunderDOMElementSSR.

You can declare your component underneath the class object just like with client rendered components but we use a different function this time.

TD.DefineComponent("my-ssr-button", MySsrButton);

This will make ThunderDOM/e aware of your button so that it can carry out automatic binding on DOM load.

If you want to take care of binding manually or you want to have all of your components in a manifest style structure, INSTEAD OF declaring the component, you can simply add your classes along side their element name into the initiation map manually like so:

document.addEventListener("DOMContentLoaded", () => {
    TD.BindThunderDOM({
        "my-ssr-button": MySsrButton,
        "my-other-component" : MyOtherComponent,
        //add as many components you want to bind!
    });
});

Your sever side HTML markup should include an attribute of "data-(your element name)"

Dotnet Core Example:

    @for (var i = 0; i < 10; i++)
    {
        <button id="foo" data-my-ssr-button>Click Me</button>
    }

As for binding functionality dynamically post DOM update. You can use:

    TD.BindThunderDOMElement(element,"my-ssr-button", MySsrButton);

To bind a component individually at any time.

If you are using HTMX to load dynamic components this would ideally be done in the "hx-on::after-request" where you can retrieve the target element.

And that's it. Interactivity is now bound to your server rendered components on the frontend! I don't know why React makes "hydration" look so difficult. :D

Script Reference:

class ThunderDOMElement{}

The base class of all ThunderDOM elements / components. Extend this class to create components.

class ThunderDOMElementSSR{}

The base class of all Server Rendered ThunderDOM elements / components. Extend this class to create SSR components.

this.component(componentHTML)

Creates the client rendered ThunderDOM component from the input html string returned by the delegate function.

this.css(path)

Attaches a CSS file to this client rendered component for styling.

this.iCss(cssString)

Allows for inline CSS styling via an input string for client rendered components.

this.bind(id, eventName, callback)

Allows for binding events easily to your component's elements.

this.getElById(id);

Returns an element: Param = A query (#id / .classname) for the root component's inner element you want to select.

this.getEl(queryString);

Shorthand for this.root.querySelector(query);, selects a shadow DOM element via query string within the root component.

this.setBindings();

The function that sets the event bindings for your SSR components.

TD.DefineComponent("my-ssr-button", MySsrButton);

Define a component so it can be bound to the ThunderDOMe (will be done automatically on dom load)

TD.BindThunderDOMElement(element,"my-ssr-button", MySsrButton);

Bind ssr component to dom element individually

TD.BindThunderDOM(classMap);

Bind all elements (run on document ready for undefined components)

A note from Ipinzi (Arrogant Pixel)

I hope you enjoy using ThunderDOM/e, I made it because I dislike working with all the frontend JS frameworks (except Svelt) and libs. I needed something much lighter, much simpler and something that was easier to understand how to work seamlessly with any backend.

All feedback and criticisms are welcome. Open an issue or email me directly.