Full reactivity with minimal code size.
<p>Count: {{ count }}</p>
<button @click="count.value++">Try it</button>
<script type="module">
import { createApp, ref } from '@wrium/wrium';
createApp(() => ({ count: ref(0) })).mount('#app');
</script>No compiler, no virtual DOM, no build config to fight with - just reactive primitives and a template compiler that reads your HTML directly.
Drop a script tag into any HTML page. No bundler, no compiler, no config to write before you can start.
ref, reactive, computed, and watchEffect with automatic dependency tracking, batched on a microtask.
Share markup across pages with app.component() - reactive props, no build tooling required.
Register your own v-xxx directives through the exact same registry built-ins use.
The entire core, minified - smaller than most single icon sets, with nothing to tree-shake.
Real generic .d.ts declarations generated from source - no hand-written types to keep in sync.
State, list rendering, computed counts, and event handling - no framework ceremony in between.
<input v-model="newTodo" @keyup.enter="addTodo" />
<button @click="addTodo">Add</button>
<ul>
<li v-for="todo in todos" :key="todo.id">
<span :class="{ done: todo.done }">{{ todo.text }}</span>
<button @click="removeTodo(todo.id)">×</button>
</li>
</ul>
<p>{{ remaining }} of {{ todos.length }} remaining</p>
<script type="module">
import { createApp, ref, reactive, computed } from '@wrium/wrium';
createApp(() => {
const newTodo = ref('');
const todos = reactive([]);
const remaining = computed(() => todos.filter(t => !t.done).length);
function addTodo() {
if (!newTodo.value.trim()) return;
todos.push({ id: Date.now(), text: newTodo.value, done: false });
newTodo.value = '';
}
function removeTodo(id) {
const i = todos.findIndex(t => t.id === id);
if (i > -1) todos.splice(i, 1);
}
return { newTodo, todos, remaining, addTodo, removeTodo };
}).mount('#app');
</script>Installation, core concepts, the full directive reference, and the plugin system - all in one place.
Get Started →