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 🙏

© 2026 – Pkg Stats / Ryan Hefner

asljs-data-binding

v0.2.4

Published

Declarative data-bind-* bindings for DOM elements with value pipes and event middleware.

Readme

data-binding

Part of Alexandrite Software Library - a set of high-quality, performant JavaScript libraries for everyday use.

Overview

asljs-data-binding provides declarative DOM bindings using explicit data-bind-* attributes. Bindings are applied with bindDataModel(root, model, options?).

There are three binding families:

  • Value bindings: write model values to textContent, innerHTML, or an attribute.
  • Event bindings: wire DOM events to model actions.
  • Context bindings: switch the model context for a descendant subtree.

Both families support lightweight reactivity through observable.watch(...) on the configured model path.

Installation

npm install asljs-data-binding

NPM Package: asljs-data-binding

Public Exports

Runtime exports:

  • bindDataModel
  • createBuiltInPipes

Type exports:

  • BindDataModelOptions
  • DataModel

Binding Contract At A Glance

  • Value bindings are path-based.
  • Event bindings are path-based.
  • Context bindings switch subtree model roots.
  • Pipe args are static strings.
  • Event actions are invoked as (event, model, element).
  • Missing or non-function actions warn instead of crashing the binding system.

Unsupported Syntax

  • No inline function-call expressions like save(item.id).
  • No computed expressions like price * qty.
  • No reactive pipe arguments.
  • No template-language control structures inside attributes.
  • No implicit two-way binding syntax.

Choosing The Right Binding Family

  • If you need to write text, then use data-bind-text.
  • If you need to write HTML, then use data-bind-html.
  • If you need to write an attribute, then use data-bind-<attr>.
  • If you need to write a DOM property, then use data-bind-prop-<name>.
  • If you need to toggle a class, then use data-bind-class-<name>.
  • If you need to handle an event, then use data-bind-on<event>.
  • If you need to switch the descendant model root, then use data-bind-context.

Safe Authoring Rules

  • Keep each binding attribute focused on one concern.
  • Prefer multiple binding attributes over overloaded single expressions.
  • Use data-bind-context instead of repeating long nested paths.
  • Keep event handler names on the model.
  • Keep pipe arguments literal unless a custom pipe is intentionally designed for string arguments.

Usage

import {
    bindDataModel
  } from 'asljs-data-binding';
import {
    observable
  } from 'asljs-observable';

const root =
  document.body;

const model =
  observable(
    { user:
        { name: 'Alex' },
      save: () => {
        console.log('saved');
      } });

const dispose =
  bindDataModel(
    root,
    model,
    {
      pipes:
        { yesno: value => value ? 'Yes' : 'No' }
    });

// later:
dispose();

Example bindings:

<div data-bind-text="user.name"></div>
<div data-bind-text="user.active | yesno"></div>
<div data-bind-html="body | wrap:'<span>':'</span>'"></div>
<button data-bind-onclick="save">Save</button>

Use data-bind-context to switch the model context for a subtree:

<div data-bind-context="user">
  <h1 data-bind-text="name"></h1>
  <button data-bind-onclick="save">Save</button>
</div>

Multiple bindings on the same element are supported and preferred when they describe different concerns:

<a
  data-bind-href="url"
  data-bind-text="label | upper"
  data-bind-class-active="isActive"
  data-bind-onclick="openDetails"
></a>

End-to-end example using context, value bindings, an event binding, and a custom pipe:

<section data-bind-context="user">
  <h1 data-bind-text="name"></h1>
  <p data-bind-text="active | yesno"></p>
  <a data-bind-href="profileUrl" data-bind-text="name | upper"></a>
  <button data-bind-onclick="save">Save</button>
</section>

Binding Syntax

Context binding

data-bind-context switches the model context for the entire descendant subtree.

General form:

data-bind-context="path"

The path is resolved against the current model. The resulting object becomes the model context for all descendant bindings.

Example — binding to a nested object:

<div data-bind-context="user">
  <h1 data-bind-text="name"></h1>
  <span data-bind-text="email"></span>
</div>

This is equivalent to writing user.name and user.email on the descendants without the context switch.

Nested data-bind-context attributes stack naturally:

<div data-bind-context="item">
  <div data-bind-context="author">
    <span data-bind-text="name"></span>
  </div>
</div>

Here name resolves relative to item.author.

Reactivity:

  • data-bind-context watches its path on the parent context
  • when the context object is replaced, all descendant bindings are rebound against the new context
  • stale watchers from the old context are removed

Null/undefined context:

  • if the path resolves to null or undefined, descendant bindings degrade gracefully following the existing nullish conventions (empty text, removed attributes, action warnings)
  • if the context later becomes a non-null object, descendants become active again

Value bindings

General form:

data-bind-<target>="path[ | pipe[:arg1[:arg2...]]]*"

Pipe arguments can be quoted when they contain characters like :.

data-bind-html="content | wrap:'<span>':'</span>'"

Supported targets:

  • data-bind-text -> textContent
  • data-bind-html -> innerHTML
  • data-bind-<attr> -> HTML attribute (for example href, title, aria-label)
  • data-bind-prop-<name> -> DOM property (for example value, checked)
  • data-bind-class-<name> -> class toggle by truthy/falsy value

Examples:

<div data-bind-text="name"></div>
<div data-bind-text="name | upper"></div>
<div data-bind-text="createdAt | date:short"></div>
<div data-bind-text="amount | currency:GBP"></div>
<div data-bind-html="content | wrap:'<span>':'</span>'"></div>
<a data-bind-href="url"></a>
<input data-bind-prop-value="name">
<button data-bind-class-active="isSelected"></button>
<div data-bind-html="body | safeHtml"></div>

Reactivity for value bindings:

  • depends only on path
  • subscribes to updates for that path
  • pipe args are static strings and are not reactive

Event bindings

General form:

data-bind-on<event>="actionPath"

Examples:

<button data-bind-onclick="activate"></button>
<a data-bind-onclick="openDetails"></a>
<form data-bind-onsubmit="save"></form>

Runtime behavior:

  • data-bind-onclick listens to click, data-bind-onsubmit listens to submit, etc.
  • action is resolved from model by actionPath
  • when action is a function, it is invoked as (event, model, element)
  • missing or non-function actions emit warnings and keep binding alive

Reactivity for event bindings:

  • depends only on actionPath
  • subscribes to updates for that path
  • handler reference refreshes when action changes

Built-ins

Value pipes:

  • string
  • number
  • currency[:code]
  • date[:format]
  • datetime[:format]
  • fixed[:digits]
  • upper
  • lower
  • json[:spaces]
  • default:value
  • safeHtml

Locale behavior:

  • by default, Intl pipes use runtime/browser locale settings
  • to force a locale, compose custom pipes using createBuiltInPipes('en-GB') in your own implementation

Error Handling

  • unknown pipe: throws
  • pipe error: exception from pipe propagates
  • missing/non-function action: warning, binding continues

Behavior at a glance:

  • data-bind-text with null or undefined renders ''.
  • data-bind-html with null or undefined renders ''.
  • data-bind-<attr> with null or undefined removes the attribute.
  • Unknown pipes throw.
  • Pipe exceptions propagate.
  • Missing or non-function event handlers warn and keep bindings alive.

Nullish behavior:

  • built-in pipes preserve null and undefined values
  • data-bind-text and data-bind-html render null/undefined as ''
  • data-bind-<attr> removes the attribute when final value is null or undefined

API Reference

Core API:

  • bindDataModel(root, model, options)

Types are exported from:

  • BindDataModelOptions
  • DataModel

Related Packages

  • For model reactivity itself, see asljs-observable.
  • For event primitives, see asljs-eventful.
  • For reusable UI elements, see asljs-components.

License

MIT License. See LICENSE for details.