Mizu Rendering Engine

repository·main·Indexed 43 days ago

https://github.com/lowlighter/mizu

A rendering engine for client-side and server-side environments that uses a directive-based syntax to transform HTML and strings into reactive or static content. It features directives for attribute binding (:attribute), CSS class and style management, event listening (@event), list rendering (*for), conditional rendering (*empty), and custom element registration (*custom-element).

Tokens
12.2K
Snippets
54
Records
69
Agent score
55%

What's inside Mizu

  1. Apply modifiers to event listeners

    main

    Modifiers are appended to the event directive using dot notation to change the behavior of the listener. Modifiers apply to all listeners within that directive.

    Common modifiers include:

    • .prevent: Calls event.preventDefault().
    • .stop: Calls event.stopPropagation().
    • .once: Registers the listener with { once: true }.
    • .passive: Registers the listener with { passive: true }.
    • .capture: Registers the listener with { capture: true }.
    • .self: Triggers only if event.target is the element itself.
    • .attach["element" | "window" | "document"]: Attaches the listener to a different target like window or document.
    • .throttle[duration]: Limits execution frequency (default ~250ms).
    • .debounce[duration]: Delays execution until inactivity (default ~250ms).
  2. Use the `$generated` variable with `*empty`

    main

    When using the *empty directive, you can access the $generated variable. This variable is a number representing the count of elements produced by the preceding *for directive.

    Note: This value might differ from the actual number of iterations if conditional directives were applied during the loop.

    <p *empty.not *text="`\`${$generated} results\``"></p>
  3. How `*text="content"` handles HTML escaping

    main

    The *text="content" directive automatically escapes HTML content.

    If you use the directive without an attribute value (e.g., <a *text>...</a>), it escapes the element's innerHTML. For example, <a *text><b></b></a> will be rendered as <a>&lt;b&gt;&lt;/b&gt;</a>, effectively treating the inner HTML as plain text.

  4. Use the !ephemeral modifier for one-time directive evaluation

    main

    The !ephemeral modifier instructs the engine to evaluate a directive exactly once and then automatically remove it from the DOM after processing. This is useful for one-off event handlers or setup logic.

    Usage Notes:

    • Directives using the * prefix can omit the asterisk when using this modifier (e.g., !directive is equivalent to !*directive).
    • Directives with placement restrictions (such as !if or !else) must also be marked as ephemeral.
    <input type="button" value="Click me!" !@click="this.value = 'Clicked!'">
  5. Access referenced elements via `$refs`

    main
    The $refs variable is a Record<PropertyKey, HTMLElement> that contains a collection of all elements marked with a *ref directive within the current subtree. You can use this object to access elements and their properties (like dataset, value, or innerHTML) in other expressions.
  6. Set up mizu.js in NodeJS or Bun

    main

    For NodeJS and Bun, install mizu.js using the JSR npm compatibility layer.

    Note: On the server-side, rendering is implicit (no *mizu attribute needed) and reactivity is disabled.

    # Install via npx (NodeJS)
    npx jsr add @mizu/render
    
    # Install via bunx (Bun)
    bunx jsr add @mizu/render
    
    # Usage
    import Mizu from "@mizu/render/server"
    await Mizu.render(`<div *text="foo"></div>`, { context: { foo: "🌊 Yaa, mizu!" } })
  7. Use the `::value` directive for bi-directional data binding

    main

    The ::value directive enables bi-directional binding between an HTML element's value attribute and a model. It is designed for use with <input>, <select>, or <textarea> elements.

    Key Behaviors

    • Array Binding: <input type="checkbox"> and <select multiple> elements will automatically bind to an array of values instead of a single value.
    • Shorthand Syntax: You can use the shorthand ::="model" instead of :: value="model".
    • Event Precedence: The model relies on input or change events to update. If you need to react to a model change, listen to the :: event rather than @input or @change to ensure the model has already been updated.

    Constraints

    • This directive must be used on elements that possess a value property. For other elements, use the : attribute directive instead.
    <select ::value="foo">
      <!--<option>...</option>-->
    </select>
  8. Conditionally render elements with the `*empty` directive

    main

    The *empty directive allows you to conditionally render an element based on whether a preceding *for directive generated any items.

    Usage Rules:

    • The *empty directive must be placed immediately after an element containing a *for directive or another *empty directive.
    • Note that the elements actually generated by the *for loop do not count towards this placement restriction; the directive itself must follow the loop container.
    • Currently, <template> elements do not have special handling.
    <article *for="const article of articles"></article>
    
    <!-- Renders only if articles is empty -->
    <p *empty>
      No results.
    </p>
    
    <!-- Renders only if articles has items -->
    <p *empty.not *text="`\`${$generated} results\``"></p>
  9. Use the `%@event="listener"` directive to trigger HTTP requests

    main

    The %@event="listener" directive allows you to listen for a dispatched Event and re-evaluate a %http directive before reacting to its Response.

    Requirements:

    • The element must also possess a %http directive.
    • It inherits all modifiers from the %http directive, as well as the RequestInit prepared by %header and %body directives.

    Dynamic URLs: Because the %http directive is re-evaluated upon the event, you can use the $event variable to dynamically compute the target URL (e.g., %http="$event ? '/foo' : '/bar'").

    <button %http="https://example.com" %@click.html>
      <!--...-->
    </button>
  10. Create element references with `*ref="name"`

    main

    Use the *ref="name" directive to create a reference to an HTML element. This allows you to access the element later via the $refs collection within the current subtree.

    When you redefine a reference with the same name, it shadows the previous value within the current subtree but does not affect the value in the parent subtree.

    <div *ref="foo" data-text="bar">
      <!-- Accessing the reference via $refs -->
      <p *text="$refs.foo.dataset.text"></p>
    </div>
  11. Use the `*clean` directive to clean up elements

    main

    The *clean directive is used to clean up an element and its children from specified content. It operates during the CONTENT_CLEANING phase. You apply it by adding the *clean attribute to an HTML element.

    <div *clean>
      <!--...-->
    </div>