Get started with VSN.js
Start with a page, give it a little state, and let VSN connect the two. VSN enhances HTML that already exists, using CFS behavior blocks and vsn-* attributes. No component renderer required.
Install
npm install vsn
The package includes JavaScript modules, a CommonJS build, TypeScript declarations, and browser builds. In a bundled application, import from vsn. For a plain HTML page, serve the package's dist/index.min.js from your own static assets.
The complete page below assumes that file is available at /dist/index.min.js. That URL is a file served by your application, not a CDN address. If your asset directory is different, change the script's src.
Your first page
Save this as an HTML page and serve it over HTTP alongside the browser build:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>My first VSN page</title>
</head>
<body>
<main id="counter">
<h1>A small counter</h1>
<p>Count: <strong vsn-bind:from="count">0</strong></p>
<button type="button" vsn-on:click="count--;">−1</button>
<button type="button" vsn-on:click="count++;">+1</button>
<button type="button" vsn-on:click="active = !active;">
Toggle status
</button>
<p vsn-show="active" hidden>The counter is active.</p>
</main>
<script type="text/vsn">
#counter {
count: 0;
active: false;
}
</script>
<script type="module" src="/dist/index.min.js" auto-mount></script>
</body>
</html>
Run the counter example, or browse all 17 examples.
What just happened?
#counterselects a behavior root. Its declarations initialize reactive state- Descendants inherit that state through their scopes
vsn-bind:from="count"writes the current count into the elementvsn-on:clickruns CFS when a button is clicked- Assignments update dependent bindings;
vsn-showtoggles the nativehiddenstate
The module's auto-mount setup reads script[type="text/vsn"] blocks and mounts the document body. It can also fetch CFS from a script's src attribute. To keep behavior source in an external .vsn file, replace the inline behavior script with:
<script type="text/vsn" src="/path/to/some.vsn"></script>
Keep the runtime module with auto-mount. The file contains plain CFS, without script tags. VSN fetches it before mounting; a nonempty src takes precedence over inline text. The extension is a naming convention, so .cfs also works. See CFS source loading for ordering and error behavior. Put plugin modules before the core module when using plugins.
CFS is a small JavaScript-like language with CSS-like selectors. It is not JavaScript inside a differently named script tag. One particularly useful detail: hyphenated names are valid identifiers, so subtraction needs whitespace. Write count - 1, not count-1.
Add a form binding
A plain vsn-bind on a form control is two-way. An explicit :from binding is a good choice for the display:
<section id="greeting">
<label>Your name <input vsn-bind="name" /></label>
<p>Hello, <span vsn-bind:from="name"></span>.</p>
</section>
<script type="text/vsn">
#greeting {
name: "Ada";
}
</script>
Add this before the existing core module script. Mount once for the page; each example does not need its own engine.
Mount explicitly
For a bundled application, create an engine, register the behavior source, and await mounting:
import { Engine } from "vsn";
const engine = new Engine();
engine.registerBehaviors(`
#counter {
count: 0;
active: false;
}
`);
await engine.mount(document.getElementById("counter"));
Run this after the markup exists, and omit the auto-mount script when taking this route. mount() does not perform the auto-loader's source fetching for you: supply the CFS to registerBehaviors() yourself. Use engine.dispose() when tearing down the engine.
For server-rendered content with serialized client state, see hydration. For signatures and options, see the Engine reference.