nom, please more


    1.0.5 • Public • Published


    No-junk JS component library with insignificant weight. If you're 17.5% too weak or 11.4% too unwilling to use heavy-weight component frameworks, but still want all the stuff in one mush:

    • Web-Components
    • Localization
    • Templates
    • Routing
    • Reactive binding
    • Debounce
    • Unique IDs
    • PSW hashing

    Plus 133.7% of all the quickility.


    Handmade master craftsmanship gives you the full-bodied low-fat experience you expect from a component framework:

    • No inheritance
    • No bundler
    • No build-step
    • No TypeScript
    • No junk

    All the folding chair comfort you ever hoped for.


    Because TURBOPUG is so bare bones, your customer's browser almost needs to be from the JavaScript-future:

    • modules & imports
    • template literals
    • Web Components
    • All the words: let, const, ...

    Yes: That's all the browsers, since a couple of years.


    Running in an up-to-date browsers your SPA doesn't need all the vanity junk. Just use a server that doesn't crack on HTML/2 push and gzipped response compression.

    Real quickility comes with not doing stuff. And thats what TURBOPUG does: not doing stuff. If you want wing chair comfort and a nurse giving you a hand, don't use TURBOPUG. If you know your JavaScript, get cracking.


    TURBOPUG is hertz-saving for computers. So somewhere someone doesn't need to burn fatty non-renewables. But keep in mind: what you do is up to you: Run your stuff on a Windows-11-VM through 5 VPNs and 6 SSH-tunnels if you like to roll like a coaler.


    TURBOPUG happened while writing an SPA in vanilla JavaScript in a reactive, event-driven design by factoring out the accidental complexity.

    Component Example

    import Comp from '../turbo/comp.js';
    import Store from '../turbo/store.js';
    export class MyCounter extends Comp {
        static get observedAttributes() {
            return ['label'];
        constructor() {
            this.#store = new Store({
                label: (value = '', event) => {
                    switch (event.type) {
                        case 'set':
                            return event.value;
                            return value;
                counter: (value = 0, event) => {
                    switch (event) {
                        case 'incremented':
                            return value + 1;
                        case 'decremented':
                            return value - 1;
                            return value;
                label: null,
                counter: 1,
        attributeChangedCallback(name, _, value) {
            switch (name) {
                case 'label':
                    this.#store.send.label({type: 'set', value});
        get label() {
            return this.#store.state.label;
        set label(value) {
            this.#store.send.label({type: 'set', value});
        render() {
            return /*html*/`
                    <span class="label">${this.#store.state.label}</span>
                    <span class="counter">${this.#store.state.counter}</span>
                <button class="decrement">Decrement</button>
                <button class="increment">Increment</button>
        bind(valElem, decBtn, incBtn) {
            const labelElem = valElem.querySelector('.label');
            this.#store.on.label((_, value) => {
                labelElem.innerText = value;
            const counterElem = valElem.querySelector('.counter');
            this.#store.on.counter((_, value) => {
                counterElem.innerText = value;
            decBtn.addEventListener('click', () => {
            incBtn.addEventListener('click', () => {
    customElements.define('my-counter', MyCounter);
    • An TURBOPUG component is defined by extending the class Comp.
    • For state management a Store is initialized and assigned onto a private variable #store. Stores are inspired by redux und made of variables that can be changed by sending events and reacting to them via reducers.
    • The 2 methods static get observedAttributes() and attributeChangedCallback(name, _, value) are part of the web-components specification.
    • A component can have a render-method which must return a rendered HTML-string. JS template strings are used for that.
    • After such a HTML-string is turned into DOM elements the bind-method is called. In which event-listeners from the DOM are attached and changes coming from the store are inserted into the DOM.

    Components are state machines

    How to program with TURBOPUG

    An TURBOPUG comp is a state machine. Programming is done via variable changes over time. I.e. setting one variable through user-input, reacting to a change, setting another variable and reacting to the change, until one change is reflected in HTML via a binding or triggers an outside variable-change-handler.

    Localization/i18n bindings

    lcz-prop and lcz-attr are used to bind to localization keys from the translations file. Syntax is:



    <p lcz-prop="textContent=LOCALIZABLE_KEY:Fallback Translation"></p>
    <input lcz-attr="value=LOCALIZABLE_KEY:Fallback Translation" type="text">

    The name of the prop or attrib to set the localization on. Can be omitted, defaults to textContent.


    The localization key to use to retrieve the value from the translations file. Fallback is value of <attrib-or-prop-name> if not found, default value textContent included.

    Localization/i18n setup

    insig must rely on script loading order to make translations available ASAP during page-loading. Translations file and LCZ-module must be setup as follows:

    <!doctype html>
    <html lang="en">
        <script src="/translations.js"></script> <!-- TRANSLATIONS FILE IS FIRST JS-FILE LOADED -->
        <!-- OTHER SCRIPT AFTERWARDS ... -->
        <!-- CONTENT COMES HERE -->
        <script src="/insig/lcz.js" type="module"></script> <!-- LCZ MODULE LOADED DIRECTLY AFTER CONTENT -->

    The localizations file must set a the property localizations on the window object. If you only need one central localizations file, use the simple object notation in which each language locale is a key, i.e. de for german or "de-CH" for swiss german:

    window.localizations = {
        de: {
            DOGS: 'Hunde',
            CATS: 'Katzen',
            DOG: 'Hund',
            CAT: 'Katze',
            DONE: 'Fertig'

    If you want to use several localization files, use the array notation in which each entry is one of the above. Use the following terse notation per file to automatically extend a previously loaded definition:

    window.localizations = (l => [...l, {
        de: {
            DOGS: 'Hunde',
            CATS: 'Katzen',
            DOG: 'Hund',
            CAT: 'Katze',
            DONE: 'Fertig'
    }])(window.localizations || []);

    The actual translations objects are merged in this case. The order in which the files are loaded in the HTML is significant: Files loaded later overwrite translation-keys from a file loaded earlier, so you can extend on base localizations.


    npm i turbopug

    DownloadsWeekly Downloads






    Unpacked Size

    35.8 kB

    Total Files


    Last publish


    • jaqmol