Skip to content
Luke-zhang-04 edited this page Apr 3, 2024 · 29 revisions

DeStagnate

License npm version tests

A lightweight (< 1 KB gzipped) wrapper around vanilla DOM methods for declarative DOM creation.

Why not just use React?

This isn't meant to be React. React has virtual DOM, hooks, and a huge ecosystem surrounding it. React 19 is supposed to have a compiler too. This is just a wrapper for when you need to create some DOM declaratively, and don't need all of React. I suppose you could use Preact, but even that involves some VDOM stuff.

Documentation

Documentation can be found at https://luke-zhang-04.github.io/DeStagnate/ for the latest version

Installation

Through NPM

# NPM
npm i destagnate --save

# Yarn
yarn add destagnate

# PNPM
pnpm i destagnate

Through curl or wget to download a bundle for browser usage

# Prodution
curl -L https://unpkg.com/destagnate@<VERSION_NAME>/dist/<FORMAT>/deStagnate.min.js > deStagnate.js
wget https://unpkg.com/destagnate@<VERSION_NAME>/dist/<FORMAT>/deStagnate.min.js

# Development
curl -L https://unpkg.com/destagnate@<VERSION_NAME>/dist/<FORMAT>/deStagnate.js > deStagnate.min.js
wget https://unpkg.com/destagnate@<VERSION_NAME>/dist/<FORMAT>/deStagnate.js

# Latest IIFE bundle
curl -L https://unpkg.com/[email protected]/dist/iife/deStagnate.min.js > deStagnate.min.js
wget https://unpkg.com/[email protected]/dist/iife/deStagnate.min.js

With a CDN

<!-- Production -->
<script src="https://unpkg.com/destagnate@version/dist/iife/deStagnate.min.js"></script>

<!-- Development -->
<script src="https://unpkg.com/destagnate@version/dist/iife/deStagnate.js"></script>

<!-- Latest -->
<script src="https://unpkg.com/[email protected]/dist/iife/deStagnate.min.js"></script>

Kitchen Sink Example

Sorta. There's way more you can do with DeStagnate. See https://luke-zhang-04.github.io/DeStagnate/docs for example code and documentation.

const divRef = DeStagnate.createRef<HTMLDivElement>()

document.getElementById("my-container")?.appendChild(
    // `createElement` can be abbreviated to `ce`
    DeStagnate.createElement(
        DeStagnate.Fragment,
        null,
        DeStagnate.createElement(
            "div",
            {
                class: "my-class",
                ref: divRef,
                onMyCustomEvent: (event: Event) => console.log(event),
            },
            DeStagnate.createElement(
                "p",
                null,
                "My paragraph",
                DeStagnate.createElement("i", null, " italic"),
            ),
        ),
        DeStagnate.createElement(
            "button",
            {
                onClick: (event) =>
                    divRef.current?.dispatchEvent(
                        new CustomEvent("mycustomevent", {detail: event}),
                    ),
            },
            "Click me!",
        ),
    ),
)

// Alternatively, you can use JSX. You will need a tranpiler, though.
document.getElementById("my-container")?.appendChild(
    <>
        <div class="my-class" ref={divRef} onMyCustomEvent={(event: Event) => console.log(event)}>
            <p>
                My paragraph
                <i> italic</i>
            </p>
        </div>
        <button
            onClick={(event) =>
                divRef.current?.dispatchEvent(new CustomEvent("mycustomevent", {detail: event}))
            }
        >
            Click me!
        </button>
    </>,
)

// Using vanilla DOM methods:
const container = document.getElementById("my-container")
const div = document.createElement("div")

div.classList.add("my-class")
div.addEventListener("mycustomevent", (event) => console.log(event))

const paragraph = document.createElement("p")

paragraph.innerText = "My paragraph"

const italic = document.createElement("i")

italic.innerText = " italic"

paragraph.appendChild(italic)
div.appendChild(paragraph)
container?.appendChild(div)

const button = document.createElement("button")

button.addEventListener("click", (event) =>
    div.dispatchEvent(new CustomEvent("mycustomevent", {detail: event})),
)
button.innerText = "Click me!"

container?.appendChild(button)

Alternatives

  • What about HTL?
    • HTL is cool, but it involves an HTML parser, which comes with its drawbacks. One upside though, you don't need to transpile to create DOM using XML-like syntax.
  • What about HTM?
    • HTM generates virtual DOM and doesn't directly create DOM nodes.
  • Why not just innerHTML?
    • You're missing dev tool support, it's a big security risk, and you'll have to deal with character escaping. Not fun. Mike Bostock goes over why innerHTML is bad in the HTL README.

Using JSX

If you're using JSX, you'll need a transpiler. Either TypeScript, or a Babel with a Plugin will work.

Typescript

You can compile with this tsconfig.json

{
    "compilerOptions": {
        "jsx": "react",
        "jsxFactory": "DeStagnate.createElement",
        "jsxFragmentFactory": "DeStagnate.Fragment"
    }
}

You can also compile with this .babelrc.json

{
    "plugins": [
        [
            "@babel/plugin-transform-react-jsx",
            {
                "pragma": "DeStagnate.createElement",
                "pragmaFrag": "DeStagnate.Fragment"
            }
        ]
    ]
}
Clone this wiki locally