Plugins can hook into compilation (onHook) and, more powerfully,
register their own v-xxx directives through the same registry that
v-model/v-show/v-text use internally - there is no special privilege
for built-ins.
// my-plugin.js
export const MyPlugin = {
install(api, options) {
// api contains: app, reactive, ref, computed, watchEffect,
// onHook, directive, compile, Scope, evalExp
// Register a new v-xxx directive
api.directive('focus', (el, exp, ctx) => {
setTimeout(() => el.focus(), 0);
});
// Directives can take an argument and modifiers too, same shape as
// Vue's: v-tooltip:top.instant="text" -> arg: 'top', modifiers: { instant: true }
api.directive('tooltip', (el, exp, { scope, evalExp, arg, modifiers }) => {
const position = arg || 'bottom';
const delay = modifiers.instant ? 0 : 300;
// ...
});
// Or hook into the compile pass directly
api.onHook('beforeCompile', (el, scope, cs) => {
// ...
});
}
};
A directive handler receives (el, expression, ctx), where ctx is
{ scope, cs, evalExp, watchEffect, ref, reactive, arg, modifiers } -
everything needed to set up a reactive effect or listener, plus arg (the
string after :, or undefined) and modifiers (an object with each
dot-suffix as a truthy key, e.g. .foo.bar -> { foo: true, bar: true }).
Register cleanup through cs (cs.addEffect(...) / cs.addListener(...))
so it's automatically torn down when the element is removed.
API stability (v1): app, directive, onHook, reactive, ref,
computed, watchEffect are the supported plugin surface and follow
semver - build against these. compile, Scope, evalExp are also passed
through for advanced cases (e.g. compiling a dynamically-created subtree),
but they mirror the compiler's internals directly and can change without a
major version bump.
import { createApp } from '@wrium/wrium';
import { MyPlugin } from './my-plugin.js';
createApp(() => ({ /* ... */ }))
.use(MyPlugin, { debug: true })
.mount('#app');
Using an unregistered v-xxx directive (forgetting to install its plugin)
reports an error through onHook('onError', ...) and logs to the console -
it never fails silently.
v-htmlSets innerHTML directly. Left out of core because it's an XSS risk if
bound to untrusted content; install it explicitly when you need it:
import { createApp, ref } from '@wrium/wrium';
import { HtmlPlugin } from '@wrium/wrium/plugins/html.js';
createApp(() => ({ htmlContent: ref('<b>Bold</b>') }))
.use(HtmlPlugin)
.mount('#app');
<div v-html="htmlContent"></div>
v-password-strengthFlags weak/common passwords as you type. Blocks an exact/substring match
against a common-password list, sequential runs (abc, 123), and
repeated characters; scores character-class variety for the rest.
v-password-strength="someRef" must point at a ref() - it writes
{ label, valid, reasons } into it on every input.
import { createApp, ref } from '@wrium/wrium';
import { PasswordStrengthPlugin } from '@wrium/wrium/plugins/password-strength.js';
createApp(() => ({ password: ref(''), strength: ref(null) }))
.use(PasswordStrengthPlugin, { minLength: 10, minScore: 'good' }) // label thresholds: weak < fair < good < strong
.mount('#app');
<input type="password" v-model="password" v-password-strength="strength" />
<p>Strength: {{ strength?.label }}</p>
<button :disabled="!strength?.valid">Submit</button>
assessPassword(password, options) is also exported directly as a pure
function, for validating the same way outside a template (e.g. before a
submit that also hits a server).
v-draggableMakes an element draggable with the mouse, touch, or pen, via a single
Pointer Events code path. v-draggable="position" must point at a
ref({ x, y }): dragging writes the new coordinates into it, and setting
position.value from application code moves the element too, since one
watchEffect drives the on-screen position either way. Movement is
automatically clamped so the element can't leave its offset parent (which
is given position: absolute automatically if it has no position set).
import { createApp, ref } from '@wrium/wrium';
import { DraggablePlugin } from '@wrium/wrium/plugins/draggable.js';
createApp(() => ({ position: ref({ x: 0, y: 0 }) }))
.use(DraggablePlugin)
.mount('#app');
<div class="box" style="position: relative">
<div v-draggable="position">Drag me</div>
</div>
<p>{{ position.x }}, {{ position.y }}</p>
Continue with Examples.