Nabbing Pleasant Monads
    TypeScript icon, indicating that this package has built-in type declarations

    0.8.11 • Public • Published


    npm version npm downloads Twitter Follow

    This project is part of the monorepo.


    Lightweight, reactive, VDOM-less UI/DOM components with async lifecycle and compatible.

    From hdom to rdom: Reactive UIs without virtual DOMs

    In many ways this package is the direct successor of, which for several years was my preferred way of building UIs. hdom eschewed using a virtual DOM to represent and maintain a dynamic tree of (UI) components and instead only required a previous and current component tree in format (aka nested, plain JS arrays w/ optional support for embedded other JS data types, like ES6 iterables, interfaces, etc.) to perform its UI updates. Yet, whilst hiccup trees are plain, simple, user defined data structures, which can be very easily composed without any libraries, hdom itself was still heavily influenced by the general vDOM approach and therefore a centralized update cycle and computing differences between the trees were necessary evils core tasks. In short, hdom allowed the illusion of declarative components with reactive state updates, but had to use a complex and recursive diff to realize those updates.

    In contrast, directly supports embedding reactive values/components in the hiccup tree and compiles them in such a way that their value changes directly target underlying DOM nodes without having to resort to any other intermediate processing (no diffing, vDOM updates etc.). is entirely vDOM-free. It supports declarative component definitions via,, ES6 classes, direct DOM manipulation (incl. provided helpers) and/or any mixture of these approaches.

    Targetted, isolated updates

    If a reactive value is used for an element attribute, a value change will trigger an update of only that attribute (there's special handling for event listeners, CSS classes, data attributes and style attribs). If a reactive value is used as (text) body of an element (or an element/component itself), only that body/subtree in the target DOM will be impacted/updated directly...

    The package provides an interface IComponent (with a super simple life cycle API), a base component class Component for stubbing and a number of fundamental control constructs & component-wrappers for composing more complex components and to reduce boilerplate for various situations. Whilst targetting a standard JS DOM by default, each component can decide for itself what kind of target data structure (apart from a browser DOM) it manages. rdom components themselves have no mandatory knowledge of a browser DOM. As an example, similar to, the wrapper provides a component which subscribes to a stream of hiccup-based scene descriptions (trees) and then translates each scene-value into HTML Canvas API draw calls.

    Async updates, scheduling & life cycle methods

    Since there's no central coordination in rdom (neither explicitly nor implicitly), each component can (and does) update whenever its state value has changed. Likewise, components are free to directly manipulate the DOM through other means, as hinted at earlier. Various rdom control constructs are dispatching component updates via a central scheduler. By default this is only a dummy implementation which processes tasks immediately. However, as usual rdom only relies on the IScheduler interface and so supports other implementations, like RAFScheduler.

    The IComponent interface is at the heart of rdom. It defines three lifecycle methods to: .mount(), .unmount() and .update() a component. The first two are always async to allow for more complex component initialization procedures (e.g. preloaders, WASM init, other async ops...). Several of the higher-order controller components/constructs too demand async functions for the same reasons.

    Because rdom itself relies for most reactive features, stream composition and reactive value transformations on other packages, i.e. and, please consult the docs for these packages to learn more about the available constructs and patterns. Most of rdom only deals with either subscribing to reactive values and/or wrapping/transforming existing subscriptions, either explicitly using the provided control components (e.g. $sub()) or using $compile() to auto-wrap such values embedded in an hiccup tree.


    BETA - possibly breaking changes forthcoming

    Search or submit any issues for this package


    This is still a young project. Even though most of the overall approach, component lifecycle and API are fairly stable by now (after ~75 commits) and used in production, so far there's only brief documentation and only few public examples. This is being worked & improved on... integration

    For the sake of deduplication of functionality and to keep the number of dependencies to a minimum, direct integration has been removed in favor of using relevant constructs, which can be used as lightweight adapters, i.e.:

    Support packages

    Related packages


    yarn add

    ES module import:

    <script type="module" src=""></script>

    Skypack documentation

    For Node.js REPL:

    # with flag only for < v16
    node --experimental-repl-await
    > const rdom = await import("");

    Package sizes (gzipped, pre-treeshake): ESM: 4.08 KB


    Usage examples

    Several demos in this repo's /examples directory are using this package.

    A selection:

    Screenshot Description Live demo Source
    Probabilistic color theme generator Demo Source
    Color palette generation via dominant color extraction from uploaded images Demo Source
    Interactive visualization of closest points on ellipses Demo Source
    Parser grammar livecoding editor/playground & codegen Demo Source
    Interactive pixel sorting tool using & Demo Source
    Demonstates various rdom usage patterns Demo Source
    Dynamically loaded images w/ preloader state Demo Source
    rdom drag & drop example Demo Source
    rdom & hiccup-canvas interop test Demo Source
    Full umbrella repo doc string search w/ paginated results Demo Source
    rdom powered SVG graph with draggable nodes Demo Source


    Generated API docs


    Currently, documentation only exists in the form of small examples and various doc strings (incomplete). I'm working to alleviate this situation ASAP... In that respect, PRs are welcome as well!

    import { $compile } from "";
    import { reactive } from "";
    import { cycle, map } from "";
    // reactive value
    const bg = reactive("gray");
    // color options (infinite iterable)
    const colors = cycle(["magenta", "yellow", "cyan"]);
    // event handler
    const nextColor = () =><string>;
    // define component tree in hiccup syntax, compile & mount component.
    // each time `bg` value changes, only subscribed bits will be updated
    // i.e. title, the button's `style.background` and its label
    // Note: instead of direct hiccup syntax, you could also use the
    // element functions provided by
        // transformed color as title (aka derived view)
        ["h1", {}, bg.transform(map((col) => `Hello, ${col}!`))],
            // tag with Emmet-style ID & classes
                // reactive CSS background property
                style: { background: bg },
                onclick: nextColor,
            // reactive button label


    Karsten Schmidt

    If this project contributes to an academic publication, please cite it as:

      title = "",
      author = "Karsten Schmidt",
      note = "",
      year = 2020


    © 2020 - 2022 Karsten Schmidt // Apache Software License 2.0


    npm i

    DownloadsWeekly Downloads






    Unpacked Size

    110 kB

    Total Files


    Last publish