Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@thi.ng/hdom

Package Overview
Dependencies
Maintainers
1
Versions
278
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@thi.ng/hdom

Lightweight vanilla ES6 UI component & virtual DOM system

  • 2.2.5
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
210
increased by7.69%
Maintainers
1
Weekly downloads
 
Created
Source

@thi.ng/hdom

npm (scoped)

As of 2018-03-03 this package is now called @thi.ng/hdom, formerly @thi.ng/hiccup-dom

About

Lightweight reactive DOM components using only vanilla JS data structures (arrays, objects, closures, iterators), based on @thi.ng/hiccup.

Benefits:

  • Use the full expressiveness of ES6/TypeScript to define, annotate & document components
  • Clean, functional component composition and reuse
  • No pre-processing / pre-compilation steps
  • No string parsing / interpolation steps
  • Less verbose than HTML, resulting in smaller file sizes
  • Static components can be distributed as JSON (or dynamically compose components, based on JSON data)
  • Supports SVG, arbitrary elements, attributes, events
  • CSS conversion from JS objects
  • Suitable for server side rendering (by passing the same data structure to @thi.ng/hiccup's serialize())
  • Fairly fast (see benchmark example below)
  • Only ~10KB minified
import * as hiccup from "@thi.ng/hiccup";
import * as hdom from "@thi.ng/hdom";

// stateless component w/ params
const greeter = (name) => ["h1.title", "hello ", name];

// component w/ local state
const counter = (i = 0) => {
    return () => ["button", { onclick: () => (i++) }, `clicks: ${i}`];
};

const app = () => {
    // root component is just a static array
    // instantiate counters w/ different start offsets
    return ["div#app", [greeter, "world"], counter(), counter(100)];
};

// start update loop (browser only, see diagram below)
hdom.start(document.body, app());

// alternatively apply DOM tree only once
// (stateful components won't update though)
hdom.createDOM(document.body, hdom.normalizeTree(app()));

// alternatively browser or server side HTML serialization
// (note: does not emit attributes w/ functions as values, i.e. the button "onclick" attribs)
console.log(hiccup.serialize(app()));
// <div id="app"><h1 class="title">hello world</h1><button>clicks: 0</button><button>clicks: 100</button></div>

Live demo | standalone example

No template engine & no precompilation steps needed, just use the full expressiveness of ES6/TypeScript to define your DOM tree. The additional benefit of using TypeScript is that your UI components can become strongly typed, since they're just normal functions, can use generics, overrides, varargs etc.

The actual DOM update is based on the minimal edit set of the recursive difference between the old and new DOM trees (both nested JS arrays). Components can be defined as static arrays, closures or objects with life cycle hooks (init, render, release).

hdom dataflow

The syntax is inspired by Clojure's Hiccup and Reagent projects, however the latter is a wrapper around React, whereas this library is standalone, more lowlevel & less opinionated.

If you're interested in using this, please also consider the @thi.ng/atom and @thi.ng/rstream packages to integrate app state handling, event streams & reactive value subscriptions. More examples are forthcoming...

Status

This project is currently still in BETA. The overall "API" is stable, but there's still further work planned on optimization and generalization beyond the standard browser DOM use cases. Furthermore, the project has been used for several projects in production since 2016.

Installation

yarn add @thi.ng/hdom

New since 2018-03-15: You can now create a preconfigured app skeleton using @thi.ng/atom, @thi.ng/hdom & @thi.ng/router using the create-hdom-app project generator:

yarn create hdom-app my-app

cd my-app
yarn install
yarn start

Usage examples

Even though the overall approach should be obvious from the code examples below, it's recommended to first study the @thi.ng/hiccup reference. It's also important to point out, that this project currently has some differences as to how some attribute and iterables are treated and/or are supported in general. This project also has additional features (e.g. life cycle hooks), which aren't needed for the static serialization use cases of hiccup. Both experiments started in early 2016, but have somewhat evolved independently and require some conceptional synchronization.

Dataflow graph SVG components

This is a preview of the upcoming @thi.ng/estuary package:

Source | Live demo

Todo list

A fully documented todo list app with undo / redo feature is here:

Source | Live demo

Cellular automata

Source | Live demo

SVG particles

Source | Live demo

JSON based components

Source | Live demo

Basic usage patterns

The code below is also available as standalone project in: /examples/dashboard

Live demo here

import { start } from "@thi.ng/hdom";

// static component function to create styled box
const box = (prefix, body) =>
    ["div",
        {
            style: {
                display: "inline-block",
                background: "#ccc",
                width: "30%",
                height: "40px",
                padding: "4px",
                margin: "2px",
                "text-align": "center"
            }
        },
        ["strong", prefix], ["br"], body];

// stateful component function
const counter = (id, from = 0, step = 1) => () => box(id, (from += step).toLocaleString());

// dynamic component function (external state, i.e. date)
const timer = () => box("time", new Date().toLocaleTimeString());

// application root component closure
// initializes stateful components
const app = (() => {
    const users = counter("users");
    const profits = counter("$$$", 1e6, 99);
    return () => ["div", ["h1", "Dashboard"], users, profits, timer];
})();

// start update loop (RAF)
window.addEventListener("load", () => start("app", app));

@thi.ng/rstream integration

TODO example forthcoming...

Benchmark

A stress test benchmark is here: /examples/benchmark

Live demo here

Based on user feedback collected via Twitter, performance should be more than acceptable for even quite demanding UIs. In the 192/256 cells configurations this stress test causes approx. 600/800 DOM every single frame, something very unlikely for a typical web app. In Chrome 64 on a MBP2016 this still runs at a pretty stable 30fps (50 frame SMA).

Authors

  • Karsten Schmidt

License

© 2016 - 2018 Karsten Schmidt // Apache Software License 2.0

Keywords

FAQs

Package last updated on 18 Mar 2018

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc