mizu.js

mizu.js

Lightweight HTML templating library for any-side rendering.

mizu.js is a JavaScript library that provides a simple and efficient way to create dynamic web pages without the complexity of a fully-fledged framework or additional setup.

Ideal for rapid prototyping, generating static HTML pages, and developers seeking to wok in a hassle-free environment.

  • No build steps
  • No configuration needed
  • Any-side rendering
  • Great for static site generation
  • Easily customizable

🌊 Fun Fact: This very page is generated using mizu.js!

Examples

Here's a collection of examples showcasing the capabilities of mizu.js.

<!-- Fetch content with HTTP -->
<section class="feed" %http="'/feed'" %response.json="articles = $content">
  <h1>Articles</h1>
  <!-- Generate content from parsed response -->
  <article *for="const { id, title, type, content } of articles" *id="id">
    <h2 *text="title"></h2>
    <pre *if="type === 'code'"><code *code[ts]="content"></code></pre>
    <div *else="type === 'image'"><img :src="content"></div>
    <div *else="" *markdown="content"></div>
  </article>
  <div *empty.not="" *text="`${${generated}} results`"></div>
  <div *empty="">No results</div>
</section>

<!-- Generate a table of content based on existing headings -->
<nav *toc[h1-h2]="'.feed'"></nav>
<!-- Define components inside a <template> and declare <slot> tags -->
<template *custom-component="say-hello">
  <div *clean.spaces="">
    <span *text="{ fr: 'Bonjour' }[$attrs.lang] ?? 'Hello'"></span>,
    <slot name="username"></slot>
  </div>
</template>

<!-- Use your newly declared component! -->
<say-hello lang="fr">
  <span #username="" *text="username"></span>
</say-hello>
<!-- Setup form -->
<section *set="{ data: { food: '🍱', quantity: 0 } }">
  <form %@submit.post="'/order'" %header[x-foo]="'bar'" %body.json="data">
    <!-- Declare some inputs -->
    <input type="number" ::value="quantity" min="0">
    <select ::value="food">
      <option *for="['🍱', '🍣', '🍥', '🍙']" :value="$value"></option>
    </select>
    <!-- Configure some buttons -->
    <button type="submit" :disabled="!quantity" :class="{ ok: quantity }">Order!</button>
    <button type="reset" @click.prevent="data.quantity = 0">Reset</button>
  </form>
</section>

Why choose mizu.js?

Any-side rendering
Compatible with most JavaScript runtimes and browsers. Templates can be rendered server-side, client-side, or using a mixture of both.
Compatibility with NodeJS, Bun and browsers is intended, but mizu.js is currently only tested with Deno as part of its early development.
Straightforward
Simply include its <script> or import statement to get started. No configuration or build steps are required.
Intuitive
Rely on HTML attributes and vanilla JavaScript expressions, no need to learn a new syntax or language.
Customizable
Make your own build using our custom builder to select specific features and reduce the final build size according to your project's needs, and create your own directives easily through developer-friendly APIs.
Open-core
Released under the AGPLv3 License and freely available at github.com/lowlighter/mizu.
A minimum of $1 monthly sponsorship grants you the right to use it under the MIT License.

Usage

mizu.js is currently in active early development.
If you encounter any issues, please report them at github.com/lowlighter/mizu/issues/new.

To utilize mizu.js, just include the following line in your HTML document:

<script type="module" href="https://mizu.sh/mizu.js">

Or to use it as a JavaScript module:

import * as Mizu from "@lowlighter/mizu"

Assets are hosted on Vercel but mizu.js is also available on npm, jsr, and CDN services that distributes npm packages such as JSdelivr.

All published versions are available in the /v/ directory. By default, the main branch is served.

Preset builds

mizu.js provides preset builds for added convenience. If you need a specific set of features, you can also use the custom builder.

This section has not been documented yet.

Concepts

Directive

A directive is a HTML attribute that has a special syntax that tells mizu.js how to process an element. The full syntax of a directive is as follows:

<tag 
*name
[tag]
.modifier
[value]
="expression"
 />

*name Directive name

Its first character usually indicates the type of directive:

[tag] Tag (optional)

Its effect depends on the directive, but it is usually treated as the directive's argument or as a way to differentiate between multiple directives with the same name.

.modifier Modifier(s) (optional)

Each directive can have one or more modifiers that alter its behavior, which is described in the directive's documentation. Multiple modifiers can be chained together.
A same modifier should be used at most once per directive, reusing it is considered undefined behavior.

[value] Modifier value (optional)

Modifiers usually accept a value that can be one of the following types:

  • boolean, defaults to true.
  • string, defaults to "" and is case-insensitive.
  • number, defaults to 0.
  • duration, defaults to 0ms (supported unit modifiers are ms, s and m).

Phase (priority)

Each directive is processed in a specific order, called a phase (or Priority).

Phase list
  • 00 META
  • 01 ELIGIBILITY
  • 02 PREPROCESSING
  • 10 TESTING
  • 11 CONTEXT
  • 21 EXPAND
  • 22 MORPHING
  • 23 TOGGLE
  • 31 HTTP_HEADER
  • 32 HTTP_BODY
  • 33 HTTP_REQUEST
  • 34 HTTP_CONTENT
  • 35 HTTP_INTERACTIVITY
  • 41 CONTENT
  • 49 CONTENT_CLEANING
  • 51 ATTRIBUTE
  • 52 ATTRIBUTE_MODEL_VALUE
  • 59 ATTRIBUTE_CLEANING
  • 61 INTERACTIVITY
  • 71 DISPLAY
  • 81 CUSTOM_ELEMENT
  • 82 REFERENCE
  • 89 CUSTOM_PROCESSING
  • 99 POSTPROCESSING

Since each directive is associated with a specific phase, the order in which they are declared on an element is usually not important.

It is not possible to use several directives with the same phase on the same element, unless it is explicitly allowed by the directive in which case they will be marked with the Multiple badge.
Using conflicting directives on the same element is considered undefined behavior.

Expression (JavaScript)

Most directives require a non-empty HTML attribute value, which will be evaluated asynchronously (meaning await is allowed) in the context of the current element upon processing.

Directives with a default value will be marked with the Default badge.

Unless specified otherwise, any expression that results in a single value is allowed.
Expressions are usually not processed in any specific way, offering access to the full capabilities of the JavaScript engine including its potential risks.

Context

All expressions will be evaluated in a specific context, which contains all the declared variables.

Depending on how you are using mizu.js, these values may be defined through the API or with directives. The latter may also define special variables (prefixed by $) depending on current processing state.

mizu.js uses @libs/reactive to track changes in the context and trigger a re-render when necessary.

Directives

General

*mizu
Priority1 — ELIGIBILITY

Enable mizu rendering for the element and its children.

<main *mizu="">
  <!--...-->
</main>
1 Restriction 1 Note $root
For performance reasons, it is not possible to specify any attribute [tag] or .modifiers with this directive.
If you are using mizu programmatically, you can chose whether to require this directive or not to enable mizu rendering using the implicit option. By default, rendering is explicit in Client-Side APIs and implicit in Server-Side APIs.

Variables

$rootHTMLElement The closest element that declares a *mizu directive.

Contextual

*set="context"
Priority11 — CONTEXT

Set a context for an element and its children.

<div *set="{ foo: 'bar' }">
  <!--<span *text="foo"></span>-->
</div>
1 Restriction 1 Note
Context must resolve to a JavaScript Object.
Context is only initialized once and is not reset upon subsequent renderings, and can be updated by other directives.

*ref="name"
Priority82 — REFERENCE

Create a reference to the element for later use.

<div *ref="foo" data-text="bar">
  <!--<p *text="$refs.foo.dataset.text"></p>-->
</div>
1 Note $refs .raw
Redefining a reference will overwrite its previous value for the rest of the subtree without affecting its value in the parent subtree.

Variables

$refsRecord<PropertyKey, HTMLElement> A record of all previously referenced elements in current subtree.

Modifiers

.raw[boolean=true] Whether to skip attribute value evaluation or not.

Conditional

*if="expression"
Priority23 — TOGGLE

Conditionally render an element.

<div *if="true">
  <!--...-->
</div>

*else="expression"
Defaulttrue Priority23 — TOGGLE

Conditionally render an element after another *if or *else directive.

<div *if="false"></div>
<div *else="false"></div>
<div *else=""><!--...--></div>
1 Restriction
Must be defined on an element immediately preceded by another element with either a *if or *else directive.

*show="expression"
Priority71 — DISPLAY

Conditionally display an element.

<div *show="true">
  <!--...-->
</div>
2 Notes
The CSS display property is set to none !important when hidden.
Unlike *if and *else directives, element is not removed from the DOM when hidden.

Iterative

*for="expression"
Priority21 — EXPAND

Render an element for each iteration.

<!--<ul>-->
<li *for="let item of items"></li>
<!--</ul>-->
1 Restriction $id $iterations $i $I $first $last
Expression can either be:
  • Any syntax supported inside for, for...in and for...of loops.
  • Any iterable object that implements Symbol.iterator.
    • Iterated key will be exposed as $key variable.
    • Iterated value will be exposed as $value variable.
  • A finite number.
    • Directive will be applied the specified number of times.

Variables

$idstring Evaluated value of the *id directive if present, or the identifier auto-generated by the directive. $iterationsnumber Total number of iterations. $inumber Current iteration index (0 indexed). $Inumber Current iteration index (1 indexed, same as $i + 1). $firstnumber Whether this is the first iteration (same as $i === 0). $lastnumber Whether this is the last iteration (same as $i === ($iterations - 1)).

*id="expression"
Priority0 — META

Hint for *for directive to differentiate generated elements.

<!--<ol>-->
<li *for="const {id} of items" *id="id"></li>
<!--</ol>-->
1 Restriction 1 Note
Must be defined on an element with a *for directive.
Identifier must be unique within the loop, any duplicate is replaced by the last occurrence found.

*empty
Priority23 — TOGGLE

Conditionally render an element after a *for directive.

<article *for="const article of articles"></article>
<p *empty.not="" *text="`${$generated} results`"></p>
<p *empty=""><!-- No results.--></p>
1 Restriction $generated .not
Must be defined on an element immediately preceded by another element with either a *for or *empty directive (elements generated by *for directive does not apply to this restriction).

Variables

$generatednumber Number of elements actually generated by the matching *for directive (this value may differ from the actual number of iterations processed, like if conditional directives were used).

Modifiers

.not[boolean] Invert conditional logic so that the element is rendered when there was at least one generated element.

Content

*text="content"
Defaultthis.innerHTML Priority41 — CONTENT

Set element's textContent.

<p *text="'...'">
  <!--...-->
</p>
2 Notes
HTML content is escaped.
Using this directive without any attribute value escapes the element's innerHTML (e.g. <a *text><b></b></a> will result into <a *text>&lt;b&gt;&lt;/b&gt;</a>).

*mustache
Priority41 — CONTENT

Enable content interpolation between mustaches ({{ and }}) from Text child nodes.

<p *mustache="">
  <!--{{ ... }}-->
</p>
1 Warning 1 Note
HTML content is escaped.
There is currently no distinction between double mustaches ({{ and }}) and triple mustaches ({{{ and }}}), but future versions may treat them differently so it is advised to only use double mustaches for now.

*code="content"
Defaultthis.textContent Priority41 — CONTENT

Set element's content after performing syntax highlighting.

<code *code[ts]="'...'">
  <!--<span class="hljs-*">...</span>-->
</code>
1 Imports 1 Note [tag] .trim
Using this will dynamically import highlight.js.
Unsupported languages defaults to plaintext

Modifiers

[string] Any supported language identifier or alias. .trim[boolean=true] Trim whitespaces and shared indentation.

*markdown="content"
Defaultthis.textContent Priority41 — CONTENT

Set element's content after performing markdown rendering.

<div *markdown="'*...*'">
  <!--<em>...</em>-->
</div>
1 Imports [tag]
Using this will dynamically import @libs/markdown.

Modifiers

[string] Load additional comma-separated markdown plugins (e.g. *markdown[emojis,highlighting,sanitize]). Supported list of plugins is available at @libs/markdown/plugins (unsupported plugins will be silently ignored).

*toc="selector"
Default'main' Priority41 — CONTENT

Create a table of contents from <h1>...<h6> found in specified selector.

<nav *toc="'main'">
  <!--<ul>...</ul>-->
</nav>
1 Restriction 1 Note [tag]
Headings elements in selected target must satisfy the following conditions:
  • Have an id attribute.
  • Have an immediate <a> child with an anchor link (which should points towards its parent id).
  • Must be in descending order level, and any level must not be skipped.
When a heading element is found, next level headings will be searched in HTMLElement.parentElement. If the parent element is a <hgroup> or has a *toc[ignore], the search will be performed in its grand-parent element instead.

Modifiers

[string] Specify which heading levels should be processed by this directive.
  • The syntax for heading levels constraints is defined as follows:
    • Expression is case-insensitive.
    • A single heading level can be specified (e.g. *toc[h2]).
      • A plus sign + may be added to also process heading elements with a higher value (e.g. *toc[h2+]).
    • A range can be defined using a minus sign - between two headings levels (e.g. *toc[h2-h4]).
  • The special value ignore is used to exclude an element from the node traversal. When used, directive must not have any .modifiers or attribute value (e.g. *toc[ignore]).

*clean
Priority49 — CONTENT_CLEANING

Clean up the element and its children from specified content.

<div *clean="">
  <!--...-->
</div>
.comments .spaces .templates .directives

Modifiers

.comments[boolean] Clean up all Comment nodes from subtree. .spaces[boolean] Clean up all spaces (except non-breaking spaces &nbsp;) from subtree. .templates[boolean] Clean up all <template> nodes from subtree after processing the subtree entirely. .directives[boolean] Clean up all known directives from subtree after processing the subtree entirely. If .comments modifier is also enabled, then comments generated by directives will be cleaned up as well.

Custom elements

*custom-element="tagname"
Priority81 — CUSTOM_ELEMENT

Register a new custom element.

<template *custom-element="my-element">
  <ul><slot name="items"></slot></ul>
</template>
2 Restrictions 2 Notes $slots $attrs .flat
Must be defined on a <template> element.
Specified tagname must satisfy the definition of a valid name.
Valid custom element names may be specified as is.
Custom elements registered this way do not use Shadow DOMs but rather have their content rendered directly.

Variables

$slotsRecord<PropertyKey, HTMLSlotElement> A record of specified #slot elements by <slot> name (unamed slot is accessible using $slots[""]). $attrsRecord<PropertyKey, string> A record of specified attributes on the custom element.

Modifiers

.flat[boolean] Replace occurences of this custom element by their content. Note that it not possible to access $slots and $attrs variables when using this modifier.

#slot
Priority0 — META

Specify target <slot> in an element defined by a *custom-element directive.

<my-element>
  <li #items=""><!--...---></li>
</my-element>
2 Notes
Elements without a #slot directive are appended to the (unamed) default slot.
Elements targetting a same slot are all appended to it in the same order they were defined.

*is="tagname"
Priority22 — MORPHING

Set an element tagname.

<div *is="'section'">
  <!--...-->
</div>
1 Warning
When tagname changes, references will also change. Any equality test with elements using this directive might not work as expected.

Events

@event="listener"
Defaultnull Multiple Priority61 — INTERACTIVITY

Listen for a dispatched Event.

<button @click="this.value = 'Clicked!'">
  <!--Not clicked yet.-->
</button>
2 Notes $event [tag] .prevent .stop .once .passive .capture .self .attach .throttle .debounce .keys
Multiple listeners can be attached in a single directive using the empty shorthand @="object" (e.g. @="{ foo() {}, bar() {} }").
  • Modifiers are applied to all specified listeners in the directive (e.g. @.prevent="{}").
  • Tags may be specified to use this syntax multiple times which can be useful to attach listeners with different modifiers (e.g. @[1]="{}" @[2].prevent="{}").
  • As HTML attributes are case-insensitive, it is currently the only way to listen for events with uppercase letters or illegal attribute characters (e.g. @="{ FooBar() {}, Foobar() {} }").
To listen for events with dots . in their names, surround them by brackets { } (e.g. @{my.event}).

Variables

$eventEvent (in listener only) The dispatched Event.

Modifiers

[string] Optional tag that can be used to attach multiple listeners to the same event (e.g. @click[1], @click[2], etc.). .prevent[boolean] Call event.preventDefault() when triggered. .stop[boolean] Call event.stopPropagation() when triggered. .once[boolean] Register listener with { once: true }. .passive[boolean] Register listener with { passive: true }. .capture[boolean] Register listener with { capture: true }. .self[boolean] Listener is triggered only if event.target is the element itself. .attach["element" | "window" | "document"] Change where the listener is attached to (using window or document can be useful to create global listeners). .throttle[duration250ms] Prevent listener from being called more than once during the specified time frame. .debounce[duration250ms] Prevent listener from executing until the specified time frame has passed without any activity. .keys[string] Specify which keys must be pressed for the listener to trigger when receiving a KeyboardEvent.
  • The syntax for keys constraints is defined as follows:
    • Expression is case-insensitive.
    • A combination can be defined using a plus sign + between each key (e.g. @keypress.keys[ctrl+space]).
    • Multiple key combinations can be specified by separating them with a comma , (e.g. @keypress.keys[ctrl+space,shift+space]).
  • The following keys and aliases are supported:
    • alt for "Alt".
    • ctrl for "Control".
    • shift for "Shift".
    • meta for "Meta".
    • space for " ".
    • key for any key except "Alt", "Control", "Shift" and "Meta".
    • Any value possibly returned by event.key.

Binding

:attribute="value"
Multiple Priority51 — ATTRIBUTE

Bind an element's attribute value.

<a :href="url">
  <!--...-->
</a>
1 Warning 3 Notes
:class and :style have specific handling described below.
Multiple attributes can be bound in a single directive using the empty shorthand :="object" (e.g. :="{ foo: 'bar', bar: true }").
Any boolean attribute defined by the HTML spec is handled accordingly (removed from the element when falsy).
Bound attributes with null or undefined values are removed from the element.

:class="value"
Multiple Priority51 — ATTRIBUTE

Bind an element's class attribute.

<p :class="{ foo: true, bar: false }">
  <!--...-->
</p>
3 Notes
Evaluated expression can be either be:
  • A string of space-separated class names (e.g. "foo bar").
  • A Record<PropertyKey, boolean> of class names mapped to their current state (e.g. { foo: true, bar: false }).
  • An Array of any of the listed supported types (e.g. [ "foo", { bar: false }, [] ]).
Initial class attribute value is preserved.
Class names with at least one truthy value are treated as active.

:style="value"
Multiple Priority51 — ATTRIBUTE

Bind an element's style attribute.

<p :style="{ color: 'salmon' }">
  <!--...-->
</p>
3 Notes
Evaluated expression can be either be:
  • A string supported by HTMLElement.style.cssText (e.g. "color: blue;").
  • A Record<PropertyKey, unknown> of CSS properties mapped to their current value (e.g. { backgroundColor: "red", "border-color": "green", width: 1 }).
  • An Array of any of the listed supported types (e.g. [ "color: blue", { backgroundColor: "red" }, [] ]).
Initial style attribute value is preserved.
Specified CSS properties values are processed in the order they are defined, regardless of whether they were marked as !important.

Modeling

::value="model"
Priority52 — ATTRIBUTE_MODEL_VALUE

Bind an <input>, <select> or <textarea> element's value attribute in a bi-directional manner.

<select ::value="foo">
  <!--<option>...</option>-->
</select>
1 Warning 1 Restriction 1 Note .event .name .value .throttle .debounce .keys
< input type="checkbox"> and <select multiple> elements will bind to an array of values.
Must be defined on an element that has a value property, such as <input>, <select> or <textarea>. For other elements, use :attribute directive instead.
It is possible to use the shorthand syntax ::="model" rather than ::value="model".

Modifiers

.event[string="input"] Change the Event that triggers the model update. It is advised to use either "input" or "change" events. .name[boolean] Automatically set the input name attribute based on the attribute's value (e.g. <input ::.name="foo" > will result into <input name="foo" >). The default is true for < input type="radio"> and < input type="checkbox"> and false for all other elements. .value[boolean] Automatically initialize the model using the nullish coalescing operator and the input value attribute if the latter is present (e.g. <input ::.value="foo" value="bar" > will assign foo with the value "bar" if it was nullish). .throttle[duration250ms] Prevent listener from being called more than once during the specified time frame. .debounce[duration250ms] Prevent listener from executing until the specified time frame has passed without any activity. .keys[string] Specify which keys must be pressed for the listener to trigger when receiving a KeyboardEvent. See @event.keys modifier for more information.

HTTP

%http="url"
Priority33 — HTTP_REQUEST

Perform a fetch() call that can be handled by %response directives.

<div %http="https://example.com">
  <!--...-->
</div>
2 Notes $event .follow .history .method .get .head .post .put .patch .delete
If the element has no %response directive attached, request is not automatically performed upon processing.
Valid URLs may be specified as is.

Variables

$eventEvent | null (in url expression only) The dispatched Event if triggered by a %@event directive, or null.

Modifiers

.follow[boolean=true] Control whether fetch() should follow redirections or not. .history[boolean] Whether to history.pushState() target URL (must be the same origin). .method[string] Set HTTP method (uppercased). This modifier should not be used multiple times. .get[boolean] Alias for .method[get]. .head[boolean] Alias for .method[head] .post[boolean] Alias for .method[post] .put[boolean] Alias for .method[put] .patch[boolean] Alias for .method[patch] .delete[boolean] Alias for .method[delete]

%body="content"
Priority32 — HTTP_BODY

Set HTTP body for a %http directive.

<div %body.json="{foo:'bar'}">
  <!--...-->
</div>
$headers .type .header .text .form .json .xml

Variables

$headersHeaders A Headers object that contains all registered headers from %header directives attached to element.

Modifiers

.type["text" | "form" | "json" | "xml"] Format body with specified type. This modifier should not be used multiple times. .header[boolean=true] Automatically set Content-Type header when using a .type modifier.
  • text: set Content-Type: text/plain.
  • form: set Content-Type: application/json.
  • json: set Content-Type: application/x-www-form-urlencoded.
  • xml: set Content-Type: application/xml.
If the header was already set, it is overwritten.
.text[boolean] Alias for .type[text]. .form[boolean] Alias for .type[form]. .json[boolean] Alias for .type[json]. .xml[boolean] Alias for .type[xml].

%response="expression"
Defaultnull Multiple Priority34 — HTTP_CONTENT

Reacts to a %http directive's Response.

<div %http="'https://example.com'" %response.html="">
  <!--...-->
</div>
$response $content [tag] .consume .void .text .html .json .xml

Variables

$responseResponse A Response object that contains the fetched data. $contentunknown A variable that contains the response.body (typing depends on which modifier is used).

Modifiers

[string] Specify which HTTP status code trigger this directive.
  • The syntax for status code constraints is defined as follows:
    • A range can be defined using a minus sign - between two numbers (e.g. %response[200-299]).
    • Multiple ranges and status can be specified by separating them with a comma , (e.g. %response[200,201-204]).
  • The following aliases (case-insensitive) are supported:
    • 2XX for 200-299.
    • 3XX for 300-399.
    • 4XX for 400-499.
    • 5XX for 500-599.
.consume["void" | "text" | "html" | "json" | "xml"] Consume response.body. Multiple usage of this modifier can result in unexpected behavior. .void[boolean] Alias for .consume[void]. .text[boolean] Alias for .consume[text]. .html[boolean] Alias for .consume[html]. .json[boolean] Alias for .consume[json]. .xml[boolean] Alias for .consume[xml].

%@event="listener"
Defaultnull Multiple Priority35 — HTTP_INTERACTIVITY

Listen for a dispatched Event and re-evaluates %http directive before reacting to its Response.

<button %http="https://example.com" %@click.html="">
  <!--...-->
</button>
1 Restriction 2 Notes $event $response $content ...
Must be defined on an element that also possess a %http directive.
This is essentially a combination of %response and @event directives.
Target URL is still set by %http directive. As it is re-evaluated, you can however use the $event value to dynamically compute the target URL (e.g.%http="$event ? '/foo' : '/bar'"). All modifiers from %http directive are inherited, along with the RequestInit prepared by %header and %body directives.

Variables

$eventEvent (in listener only) The dispatched Event. $responseResponse A Response object that contains the fetched data. $contentunknown A variable that contains the response.body (typing depends on which modifier is used).

Modifiers

... Inherited from @event and %response directives. See their respective documentation for more information.

Processing

*once
Priority99 — POSTPROCESSING

Render an element once and skip subsequent updates.

<div *once="">
  <!--...-->
</div>

*refresh="interval"
Priority99 — POSTPROCESSING

Force an element to be processed again at a specified interval (in seconds).

<div *refresh="1.5">
  <!--<time *text="new Date()"></time>-->
</div>
2 Warnings 3 Notes
Context is recreated starting from the initial root context and the element itself, meaning that anything computed in-between is not available. To prevent unexpected behavior, it is recommended to only use this on elements that can be rendered independently.
Avoid using it on iterative directives such as *for as the *refresh directive will be duplicated for each generated element.
Target element will be rendered regardless of any detected changes. This directive is thus useful to update content that cannot be directly observed, but it is advised to use this sparingly to avoid performance issues.
Set the interval to null to clear the refresh.
If the element is commented out by a directive, refresh is automatically cleared.

*eval="expression"
Priority89 — CUSTOM_PROCESSING

Evaluate a JavaScript expression in the context of the element.

<div *eval="console.log('$data')">
  <!--...-->
</div>
1 Warning 1 Note
Usage of this directive is discouraged and it is recommended to use alternative directives whenever possible for improved maintainability and security reasons. It is nevertheless still offered to help covering edge cases.
It is executed after the element and all of its children have been completely processed.

*skip
Priority2 — PREPROCESSING

Prevent an element from being processed.

<div *skip="">
  <!--<p *text="foo"></p>-->
</div>

Testing

~test="expression"
Multiple Priority10 — TESTING

Special directive for testing purposes.

<samp ~test[testing].text="'...'">
  <!--...-->
</samp>
1 Warning [tag] .text .eval .comment
Intended for testing purposes only. This is provided for developers that want to test their custom directives in isolation, without having to rely on other directives.

Modifiers

[string] Any existing Phase name (e.g. ~test[testing], defaults to Phase.TESTING). Directive will be executed during the specified phase before any other directive of said phase, which can be used to simulate specific scenarios. .text[boolean] Set element's textContent with expression result. .eval[boolean] Evaluate a JavaScript expression in the context of the element. .comment[boolean] Change the element to a Comment if expression is truthy (and revert it back otherwise).

API

This section has not been documented yet.

Full API documentation is available at jsr.io/@mizu/mizu.

FAQ

This section has not been documented yet.