Nomini

repository·main·Indexed 41 days ago

https://github.com/nonnorm/nomini

A lightweight (~2kb) library for reactive HTML and partial page updates. Nomini blends reactive state management (via nm-data and nm-bind) with AJAX-driven DOM replacement using $fetch, $get, and $post. It is available in two flavors: Core for basic data-binding and Full for added AJAX support, form wiring (nm-form), and a tiny templating system (nm-use).

Tokens
3.5K
Snippets
14
Records
21
Agent score
51%

What's inside Nomini

  1. Overview of Nomini

    main

    Nomini is a lightweight (~2kb) library designed for reactive HTML and partial page updates. It combines the reactive state capabilities of Alpine.js with the AJAX-driven partial page updates of htmx and Datastar.

    Key capabilities include:

    • Adding reactive state directly within HTML.
    • Binding DOM properties and classes with automatic dependency tracking.
    • Using inline event handlers to listen to any event.
    • Performing AJAX requests to replace specific parts of a page.
    • Maintaining a declarative and local development model.

    Nomini follows a mental model of Boring HTML + islands of reactivity + server-driven pages.

  2. Handle Nomini lifecycle events with init and destroy

    main

    Nomini dispatches lifecycle events on elements as they are managed. These events do not bubble.

    • init: Dispatched when an element is initialized by Nomini.
    • destroy: Dispatched when an element is about to be swapped out by Nomini.

    You can respond to these events using nm-bind by prefixing the event name with on (e.g., oninit or ondestroy). You can also append a debounce duration to the event name using the format on[event][ms] (e.g., oninit.debounce2000).

    <!-- Trigger an action on init with a 2000ms debounce -->
    <p nm-bind="{ 'oninit.debounce2000': () => $get('/refresh') }"></p>
  3. Handle fetch errors globally with fetcherr

    main

    When a $fetch request fails or returns a non-2xx response code, Nomini dispatches a fetcherr event. Unlike lifecycle events, fetcherr bubbles outside the scope, allowing you to implement a global error handler at a higher level in the DOM tree.

    The event's detail property contains:

    • err: The error message.
    • url: The URL of the failed request.
  4. Choose a Nomini flavor

    main

    Nomini is available in two main flavors depending on your needs:

    Core

    Size: <800 bytes (<1.5kb uncompressed) Best for: Featherweight event and data-binding, ideal for integration with advanced hypermedia libraries. Includes:

    • nm-data (reactive data scopes)
    • nm-bind (property binding)
    • nm-ref (element references)
    • Standard helpers: $dataset, $watch, $dispatch

    Full

    Size: 1.8kb (4.5kb uncompressed) Best for: Projects needing syntactical sugar and AJAX support. Includes:

    • Everything in Core
    • nm-form (automatic form wiring)
    • Event modifiers
    • Fetch helpers and reactive fetch variables
    • CSS transition support for fetch
    • nm-use (tiny templating system)
    • Advanced helpers: $persist
  5. What Nomini is not

    main

    Nomini is a minimal library and is not intended to be used as:

    • A template language.
    • A performant virtual DOM.
    • A full-featured set of helpers for every possible use case.
    • A global state management system.
  6. Declare reactive data with nm-data

    main

    Use the nm-data attribute to declare a scope of reactive JavaScript data. This data is accessible to any nm- attributes within that same scope. Note that scopes are not inherited.

    • Local Properties: Any key starting with an underscore (e.g., _saved) will not be automatically sent to the server when using helpers like $get.
    • Computed Properties: Since the data scope is a standard object, you can define member functions to compute properties. Inside these functions, this refers to the data scope, not the DOM element.
    <div nm-data="name: 'Jeff'">
      <!-- content here -->
    </div>
    
    <div nm-data="first: 'Pac', last: 'Man', full() { return `${this.first} ${this.last}` }">
        <p nm-bind="textContent: () => full()"></p>
    </div>
  7. Install Nomini via CDN

    main

    To use Nomini via a CDN, include the following script tag in the <head> of your HTML document. The defer attribute is used to ensure the script is loaded without blocking HTML parsing.

    <script defer src="https://cdn.jsdelivr.net/gh/nonnorm/nomini@0.3.0/dist/nomini.min.js"></script>
  8. Watch reactive variables with $watch

    main

    The $watch helper takes a callback that runs once on initialization and subsequently whenever its dependent reactive variables change.

    <input name="text" nm-data nm-form nm-bind="oninit: () => $watch(() => console.log(text))">
  9. Swap content with nm-use

    main

    The nm-use attribute allows you to grab the contents of a <template> element by its id and swap it into the current element.

    • Slots: Supports <slot> elements; the current element's content is moved into the slot.
    • Props: Props are passed through via the inherited nm-data scope and data-* attributes.
    <template id="card">
        <h2 nm-bind="textContent: () => title"></h2>
        <slot></slot>
    </template>
    
    <section nm-use="card" nm-data="title: 42">
    What is the answer to life, the universe, and everything?
    </section>
  10. Bind properties and events with nm-bind

    main

    The nm-bind attribute binds element properties or event listeners to JavaScript expressions.

    Requirements:

    • All values in a bind must be arrow functions.
    • The function is called once on initialization and again whenever any reactive data it depends on changes.

    Usage Patterns:

    • Property Binding: Bind to properties like textContent or style.backgroundColor.
    • Event Listeners: Supports all DOM events (e.g., onclick, oninput, onresize). The callback can accept an event parameter.
    • Class Support: Bind to classes using the class.<classname> syntax. The bind function must return a boolean.
    • Nested Binds: Use dot notation for one level of nesting (e.g., style.color). If using dots, the key must be wrapped in quotes.
    • Async Support: Binds are automatically awaited. Caution: Accessing reactive properties after an await may break reactivity.
    <!-- Basic property bind -->
    <p nm-bind="textContent: () => 'Lorem '.repeat(12)"></p>
    
    <!-- Reactive data bind -->
    <div nm-data="text: ''">
        <input nm-bind="oninput: () => text = this.value">
        <p nm-bind="textContent: () => text"></p>
    </div>
    
    <!-- Event listener -->
    <button nm-bind="onclick: () => alert('OW!')">Click Me!</button>
    
    <!-- Nested style bind (requires quotes) -->
    <section nm-bind="'style.backgroundColor': () => 'lightgreen'">
        Words words words
    </section>
    
    <!-- Class binding -->
    <button nm-data="red: false" nm-bind="{
        'class.demo-red': () => red,
        onclick: () => red = !red
    }">
        I'm angry
    </button>
  11. Dispatch custom events with $dispatch

    main

    Use $dispatch to trigger a custom event on the current element. These events can be listened to by nm-bind on parent elements.

    $dispatch("my-event")
    $dispatch("scary", { run: "away" }) // detail property
    $dispatch("help-me", { so: "alone" }, { bubbles: false }) // options property