Reference
Utilities
Functions the library itself uses internally and publishes on V. They all also
exist as a direct import, from voodoojs/utils, for anyone who builds the project
with a bundler.
Identifiers and time
| Function | Returns |
|---|---|
V.uuid() | UUID v4. Uses crypto.randomUUID when available, with two fallbacks |
V.uid(prefix?) | Short identifier, useful for element ids |
V.sleep(ms) | Promise that resolves after the given time |
V.parseDuration(value, fallback?) | Milliseconds from 300, '300ms', '1.5s', '2m', '1h' |
V.uid('field-'); // 'field-k3f9a2'
V.parseDuration('1.5s'); // 1500
V.parseDuration(null, 99); // 99
parseDuration accepts null because the most common source is a
getAttribute that may not exist.
Higher-order functions
debounce and throttle
const search = V.debounce(loadProducts, 300);
search('mu');
search('mug'); // only this one runs
search.cancel(); // drops the pending call
search.flush(); // runs now, without waiting
const saveNow = V.debounce(save, 1000, true); // leading edge
const track = V.throttle(measureScroll, 100);
window.addEventListener('scroll', track, { passive: true });
once and memoize
const start = V.once(() => createConnection());
start();
start(); // returns the same connection
const compute = V.memoize((a, b) => expensiveOperation(a, b));
compute.cache.clear();
const byId = V.memoize(load, (id) => String(id)); // key of your own
V.once on the global object is the event bus
(V.once('event', handler)). The utility that runs a function a single time is in
the direct import: import { once } from 'voodoojs/utils'.
Objects and arrays
| Function | What it does |
|---|---|
V.clone(value) | Deep copy. Uses structuredClone when it exists; understands Date, Map and Set |
V.merge(target, ...sources) | Deep merge. Arrays are replaced, not concatenated |
V.groupBy(list, keyOrFn) | Groups into an object |
V.unique(list, keyOrFn?) | Removes duplicates |
V.chunk(list, size) | Breaks into pieces |
V.sortBy(list, keyOrFn, direction?) | Sorts without changing the original |
V.get(object, path, fallback?) | Reads a nested path, safely |
V.set(object, path, value) | Writes, creating the objects in between |
V.random(min, max), V.sample(list) | Integer in the range, and any item |
V.merge({ a: { b: 1 } }, { a: { c: 2 } }); // { a: { b: 1, c: 2 } }
V.unique(points, (p) => p.x + ',' + p.y);
V.sortBy(products, 'price', 'desc');
V.get(data, 'list.0.name', 'no name');
V.set(form, 'items.0.qty', 2);
Two details that avoid surprises: merge modifies the first object, pass
{} in front when you want to preserve it. And sortBy compares text with
localeCompare and numeric ordering, which puts item 2 before
item 10; null values go to the end.
Text
V.slugify('Crème Brûlée'); // 'creme-brulee'
V.slugify('My Post', '_'); // 'my_post'
V.truncate('A rather long text', 10); // 'A rathe...'
V.truncate('A rather long text', 10, '…'); // 'A rather…'
V.capitalize('voodoo'); // 'Voodoo'
V.titleCase('JAVASCRIPT feels'); // 'Javascript Feels'
V.escapeHtml('<b>hi</b>'); // '<b>hi</b>'
V.stripTags('<b>hi</b>'); // 'hi'
escapeHtml is the safe way to assemble HTML by hand.
stripTags removes tags in a simple way and does not work as a defence
against hostile content. The security page explains the
difference.
Formatters
They all use the default locale and currency, both adjustable:
V.setFormatDefaults('pt-BR', 'BRL');
The bootstrap already sets this up from V.config.locale and
V.config.currency.
| Call | Result |
|---|---|
V.formatCurrency(1234.5) | R$ 1.234,50 |
V.formatCurrency(99, { currency: 'USD', locale: 'en-US' }) | $99.00 |
V.formatNumber(1234.5678) | 1.234,568 |
V.formatNumber(0.75, { style: 'percent' }) | 75% |
V.formatDate(new Date()) | 29/08/2026 |
V.formatDate(date, 'long') | 29 de agosto de 2026 |
V.formatDate(date, 'DD/MM/YYYY HH:mm:ss') | text mask |
V.relativeTime(Date.now() - 300000) | há 5 minutos |
V.formatFileSize(1536) | 1.5 KB |
V.formatPercent(0.256, 1) | 25,6% |
formatDate accepts a Date, a timestamp or ISO text, and returns empty
text for an invalid date. The named formats are long, full,
time and datetime; the text mask understands YYYY,
YY, MM, DD, HH, mm and
ss; and an object is passed straight to Intl.DateTimeFormat.
Environment
| Member | What it is |
|---|---|
V.isBrowser | Is there a DOM? |
V.device | Getters for touch, size, motion and theme |
V.screen | Reactive object with width, height and breakpoints |
V.network | Reactive object with the state of the connection |
V.clipboard | copy and read |
Inside HTML, the last four appear as $screen, $network,
$device and $clipboard. Because screen and
network are reactive, an expression that reads them updates on its own when the
window changes size or the connection drops.
<div v-data="{}">
<p>Width: { $screen.width }px</p>
<p>Is mobile: { $screen.mobile }</p>
<p>Online: { $network.online }</p>
<p>Touch: { $device.touch }</p>
<button @click="$clipboard.copy('PROMO10')">Copy coupon</button>
</div>
Importing directly
import { debounce, formatCurrency, slugify, once } from 'voodoojs/utils';
This entry point does not load the DOM runtime, so it works in Node as well, it is the way to reuse the formatters on the server without dragging in the whole library.