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

@alwatr/bind

v9.32.0

Published

A high-performance and lightweight binding utility for unidirectional data flow and reactive DOM/context interactions.

Readme

🔗 @alwatr/bind

A high-performance, lightweight reactive DOM binding utility for unidirectional data flow.

@alwatr/bind is a framework-agnostic, low-overhead library that maps reactive data sources (Signals) directly into HTML elements using declarative attributes. It allows you to build highly dynamic, interactive, and responsive user interfaces with zero virtual DOM overhead, surgical DOM updates, and complete compile-time type safety.


🧠 Architectural Philosophy

In traditional modern frameworks, updating state triggers virtual DOM reconciliation or component-wide re-renders. @alwatr/bind takes a different, highly optimized approach:

  1. Reactive Projections (ViewModels): Instead of binding raw, complex domain signals directly to the UI, you define flat ViewModels inside namespaces. These ViewModels project complex domain states into flat records of presentation-ready primitives (string, number, boolean, null, undefined).
  2. Surgical DOM Updates: Attributes on DOM elements act as binding anchors. The library hooks directly into the ViewModel's updates and modifies only the targeted text nodes or attributes—without re-running components or diffing trees.
  3. Decoupled Binding: Views declare what to bind in HTML (bind-text="user.fullName"), and the JS controller defines how that data gets derived. This keeps your HTML extremely readable and completely separates presentation from business logic.

✨ Key Features

  • Zero Virtual DOM Overhead: Updates map directly to element.textContent, element.value, or attributes.
  • 🎯 Surgical Reactivity: Only the DOM elements bound to the modified properties will re-render.
  • 🛡️ Cursor Preservation Guard (bind-value): Binds input element values securely, checking for changes before writing to the DOM. This guards against the browser resetting the text cursor position while typing in an input field.
  • 💡 Presence-Aware Attribute Binding (bind-attrib):
    • boolean values toggle the presence of the attribute (perfect for disabled, checked, hidden).
    • null/undefined values remove the attribute from the DOM.
    • Primitive values set the attribute value as a string.
  • 💤 Lazy Viewport Evaluation (lazy-bind): Defer binding registration and signal subscription until the element physically enters the viewport (using IntersectionObserver via @alwatr/directive). This is ideal for off-screen cards, slow-loading inputs, or heavy dashboard elements.

🚀 Quick Start

1. Register Bind Directives

Call setupBindDirectives() at your application's bootstrap phase to register the directives.

import {setupBindDirectives} from '@alwatr/bind';

// Register bind-text, bind-value, and bind-attrib directives
setupBindDirectives();

2. Define your Domain Signal

Define the single source of truth for your feature.

import {createState} from '@alwatr/signal';

interface User {
  firstName: string;
  lastName: string;
  cart: Array<{id: number; price: number}>;
  isLoading: boolean;
}

export const userSignal = createState<User>({
  name: 'user-domain-signal',
  initialValue: {
    firstName: 'Ali',
    lastName: 'Mihandoost',
    cart: [],
    isLoading: false,
  },
});

3. Create a Presentation ViewModel

Project your rich domain model into a flat record of presentation-ready primitives.

import {service_binding} from '@alwatr/bind';
import {userSignal} from './user-signal.js';

// Registers 'user.fullName', 'user.cartIsEmpty', and 'user.showLoading'
service_binding.createViewModel('user', userSignal, (u) => ({
  fullName: `${u.firstName} ${u.lastName}`,
  firstName: u.firstName,
  cartIsEmpty: u.cart.length === 0,
  showLoading: u.isLoading,
}));

4. Declare Bindings in HTML

Use the declarative attributes to bind elements to the ViewModel.

<!-- Binds textContent to 'user.fullName' -->
<h2 bind-text="user.fullName">Loading user...</h2>

<!-- Binds input value with cursor position preservation -->
<input
  type="text"
  bind-value="user.firstName"
  on-input="ui_edit_first_name:$value"
/>

<!-- Binds 'disabled' attribute based on boolean state, and 'aria-busy' based on loading -->
<button bind-attrib="disabled=user.cartIsEmpty; aria-busy=user.showLoading">Checkout</button>

<!-- Lazy loading: updates only when scroll brings the card into viewport -->
<div
  bind-text="user.fullName"
  lazy-bind
></div>

📚 API Reference

setupBindDirectives()

Initializes and registers the @alwatr/bind directives eagerly/lazily. Must be called before DOM parsing (typically at entrypoint load).

service_binding

A singleton registry of presentation view models.

service_binding.createViewModel(namespace, sourceSignal, project)

Registers a reactive ViewModel.

  • namespace (string): Unique namespace identifier (e.g., 'user').
  • sourceSignal (IReadonlySignal<S>): The source signal holding domain state.
  • project ((value: S) => Record<string, BindingValue>): The projection function.

service_binding.getViewModel(namespace)

Retrieves the read-only computed signal mapping of the namespace. Returns null if not found.

service_binding.removeViewModel(namespace)

Destroys the ViewModel computed signal, unsubscribing from the source signal, and removes it from the registry.


🧩 HTML Attribute Directives

bind-text="namespace.property"

Sets the element's textContent to the string value of the ViewModel's property. Maps null/undefined to ''.

bind-value="namespace.property"

Sets the element's value attribute (for inputs, selects, textareas). Features a DOM write guard:

if (inputEl.value !== nextValue) {
  inputEl.value = nextValue;
}

This ensures that user input typing feels smooth and the text cursor does not reset or jump to the end of the input field.

bind-attrib="attr1=namespace.prop1; attr2=namespace.prop2"

Binds element attributes to ViewModel properties. Multiple attributes are semicolon-separated.

  • Boolean values:
    • true: Sets the attribute with an empty string value (e.g., disabled="").
    • false: Removes the attribute entirely from the element.
  • Nullish values (null/undefined): Removes the attribute entirely.
  • Other values: Sets the attribute value coerced as a string.

lazy-bind

When placed alongside any of the above binding attributes, the directive delays its ViewModel subscription and DOM update cycle until the element intersects with the viewport. This dramatically boosts initial boot time and reduces active subscriptions for long or heavy pages.


📄 License

Licensed under the MPL-2.0 License.