Basic usage


Vanillin's starting point is bindDOM. bindDOM's signature is similar to metaesEval. For example:

bindDOM(`<button>Click</button>`, console.log);

will pass HTMLButtonElement element throught success callback when evaluation finishes.

Then, you can add element to the DOM:

document.body.appendChild(await uncpsp(bindDOM)(`<button>Click</button>`));

It's important to note the uncpsp is required, not uncps, because Vanillin by default splits work into 16ms blocks which makes synchronous result unlikely unless is trivial and fits into 16ms block.

If Vanillin runs in a web browser, DOM elements like HTMLButtonElement are created using browser's DOMParser. DOMParser creates Document with elements inside its <head> or <body>, but Vanillin extracts them right away and returns single element or array of elements (but not NodeList) depending on what was provided as a string.

Existing elements

bindDOM allows to use already existing DOM objects. For example, part of your website could look like:

<button onclick="console.log('hello world')">click</button>

Which allows you to write:

bindDOM(document.querySelector("button"), console.log, console.error);

Read more at api reference.

Rendering text using bind

Consider this example:

bindDOM(`<span bind>text</span>`, (element) => document.body.appendChild(element), console.error, {
  text: "hello world"

bind attribute makes Vanillin will:

  • get textContent of currently evaluated element and treat it as JavaScript expression,
  • evaluate expression and set result back to textContent of that element.

Think of it as a template pattern, but there is no special language, there are JavaScript scripts which should evaluate to a value.

Template expressions like <span>{{value}}</span> are not supported out of the box, but possible to implement when extending Vanillin.

Attributes binding

Attributes binding stands for setting values to elements' attributes. There are few ways you can do that. First one is:


bind-attrs is a low level tool which can be used used when list of attributes which should be bound is dynamic.


  const toBind = ["href"];
<a href="someValue" bind-attrs="toBind">Click me</a>

The logic is as following:

  1. For each item item in toBind,
    1. read value of attribute with name equal to item and store it under some value value,
    2. evaluate value in current environment as save its result in result,
    3. set attribute's value to be result.

:attr syntax

Alternatively, you can use :href syntax and greatly simplify the logic:

<a :href="someValue">Click me</a>

You need to do it for each attribute separately which in most of the cases should be the preferred way.

script tag

There are several rules to remember about <script>. <script>:

  • is evaluated in similar way to native <script>, but in case of Vanillin, code is evaluated with metaES. Both inline code and src attribute based elements are supported.
    • loading of scripts configured with src attribute is handled by Vanillin custom loader. It can be overriten.
  • can additionally be configured with observe attibute, which will make tags body to reevaluate when any automatically observed variables changes. TODO: This could be enabled by default?
  • doesn't have to be added to Document to be evaluated, it is evaluated immediately.
  • doesn't create additional environment for itself:
const environment = createEnvironment();
  `<script>var foo='bar'</script>`,
  () =>
    // prints `bar` because variable `foo` was set in closest surrounding environment.

script attribute

script attribute will make code contained in this attribute to be evaluated in a context where this is bound to owning element:

bindDOM(`<textarea script="initTextarea(this)></textarea>`, console.log, console.error, {
  initTextarea(element) {
    // do some logic HTMLTexareaElement element

script attribute will create additional environment:

const environment = {};
  `<div script="var foo='bar'"></div>`,
  () =>
    console.log(; // undefined