Getting started
Installation and your first file
Voodoo.js is a finished file. You download it, drop it next to your HTML, point a tag at it, and that is it. There is no installer, no build step, and no mandatory config file.
1. Pick and download the file
Three files are published. They are all the same project, cut at different points. Pick one.
| File | What is inside | Gzip | Download |
|---|---|---|---|
voodoo.core.min.js |
Reactivity, expressions, components, chainable DOM, state directives, rendering, events and requests by attribute | 42 KB | download |
voodoo.min.js |
The above, plus forms with validation, masks, the full UI kit, drag and drop, dialogs, toasts and sound | 79 KB | download |
voodoo.full.min.js |
Everything, plus charts, physics animation, the router, languages, the reactivity inspector and 29 ready-made components | 124 KB | download |
When in doubt, start with voodoo.min.js. It covers most pages. Switch to the full
one the day you need a chart, spring animation, the router, languages or the ready-made
components. Switching means rewriting the src of the tag: the HTML you already
wrote stays exactly the same.
From the terminal:
curl -L -o voodoo.min.js https://github.com/kwy404/Voodoo.js/raw/main/packages/voodoojs/dist/voodoo.min.js
Or download the whole repository from the Code button, or from the
v0.5.0 release, and take
the files out of packages/voodoojs/dist/. Each file has a .map next to
it; copy both if you want to debug the original code in the inspector.
2. Point a tag at the file
<script src="voodoo.full.min.js" defer></script>
Done. There is no V.init() to call: the library starts on its own as soon as the
page is ready, publishes the global V object (and Voodoo, the same
object), applies the saved theme, applies the saved palette and walks
document.body binding the v-* attributes.
defer makes the browser finish reading the HTML before running the file. Without
it, the library starts earlier and the MutationObserver ends up doing the work
again — it works, but it costs more.
3. Write HTML
<div v-data="{ n: 0 }">
<button @click="n++">Clicked { n } times</button>
</div>
Open the file in the browser. Click. The number changes. That is the whole cycle.
Your first file, line by line
Create an index.html next to the voodoo.min.js you downloaded:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My first Voodoo</title>
<script src="voodoo.full.min.js" defer></script>
</head>
<body>
<div v-data="{ name: '', count: 0 }">
<input v-model="name" placeholder="Your name">
<h1>Hello, { name || 'stranger' }!</h1>
<button @click="count--">-</button>
<strong>{ count }</strong>
<button @click="count++">+</button>
<p v-show="count > 5">You have clicked a lot.</p>
</div>
</body>
</html>
This is the result, running right here:
<div v-data="{ name: '', count: 0 }">
<input v-model="name" placeholder="Your name">
<h3>Hello, { name || 'stranger' }!</h3>
<div class="linha">
<button @click="count--">-</button>
<strong>{ count }</strong>
<button @click="count++">+</button>
</div>
<p v-show="count > 5">You have clicked a lot.</p>
</div>
-
<script src="voodoo.full.min.js" defer>loads the library. -
v-data="{ name: '', count: 0 }"creates a scope: two variables that hold for that<div>and for everything inside it. -
v-model="name"binds the field to the variable in both directions. Type, and the variable changes; change the variable, and the field changes. -
{ name || 'stranger' }is interpolation: it writes the value into the text and updates itself. -
@click="count++"runs the expression on click and notifies whoever depends oncount. -
v-show="count > 5"shows the paragraph only while the condition is true.
What to notice: you did not write a single line of loose JavaScript. There is no
querySelector, no addEventListener, no render function. Open the
inspector after it loads: the v-model, @click and v-show
attributes are gone. What is left is clean HTML.
Avoiding the flash of raw content
Between the browser painting the HTML and the library starting there is an instant where the raw
text shows on screen — braces of the interpolation included. v-cloak solves it: the
library removes the attribute when it finishes mounting that stretch.
<style>
[v-cloak] { display: none !important; }
</style>
<div v-cloak v-data="{ loading: true }">
<p>{ loading ? 'Loading...' : 'Ready' }</p>
</div>
The [v-cloak] rule already ships in the CSS the library injects, but declaring it in
your own file guarantees it exists before the first frame — which is exactly the moment that
matters.
Configuring from the tag itself
The fastest way to configure is with attributes on the script tag, without writing any JavaScript at all:
<script
src="voodoo.full.min.js"
data-base-url="https://api.example.com"
data-locale="en-US"
defer
></script>
| Attribute | Effect |
|---|---|
data-manual | Does not start on its own. You call V.start() when you want to |
data-defer-init | The same as data-manual |
data-prefix | Changes the attribute prefix, for example data-v- |
data-base-url | Base URL for V.http requests and for the HTTP directives |
data-locale | Locale used by the date, number and currency formatters |
data-devtools | Turns on detailed warnings in the console |
data-no-styles | Does not inject the CSS for the UI components |
data-no-observer | Turns off the MutationObserver that initializes HTML created later |
data-keep-attributes | Keeps the v-* attributes in the HTML after they are processed |
The full list of options, with the default value of each, is in the configuration reference.
When you need data-manual
Automatic start-up happens early, on purpose. If your page registers components, its own directives or global data in another file, that registration has to happen before the first sweep — otherwise the library walks past a tag it does not know yet.
<script src="voodoo.full.min.js" data-manual defer></script>
<script src="my-components.js" defer></script>
<script defer>
V.config.locale = 'en-US';
V.config.currency = 'USD';
V.http.setBaseURL('https://api.example.com');
V.start();
</script>
Whoever calls V.start() is always the last script in the list. Any file that
registers a component, a directive or data goes in before it.
A prefix that passes strict HTML
If your HTML validator complains about v-text, change the prefix:
<script src="voodoo.full.min.js" data-prefix="data-v-" defer></script>
<div data-v-data="{ n: 0 }">
<button data-v-click="n++">Add</button>
<b data-v-text="n"></b>
</div>
The library always accepts data-v-name, even when the configured prefix is another
one. The :attribute and @event shorthands keep working in both modes.
Checking that it worked
<script>
document.addEventListener('voodoo:ready', (e) => {
console.log('Voodoo', V.version, 'started on', e.detail.root);
});
</script>
If the console prints the version, the library loaded and mounted. If it prints nothing, the
src path is wrong — the network tab of the inspector confirms that in a second.