Build reactive interfaces without the framework weight.
Udodi is a lightweight, zero-dependency JavaScript UI framework with a focused API and built-in application primitives.
Udodi is a lightweight, zero-dependency JavaScript UI framework with a focused API and built-in application primitives.

import { effect, reactive } from "udodi";
const state = reactive(
{ count: 0 },
{
interceptors: {
// Keep count non-negative.
count(value) {
return Math.max(0, value);
},
},
}
);
effect(() => {
element.textContent = state.count;
});
// Fine-grained update
state.count++;Udodi tracks dependencies where reactive data is read, so changes update only the effects and interface parts that depend on that state, instead of broad component re-renders.
Reactive state can also use interceptors to control or transform assignments before values are applied, keeping state rules close to the data itself. The result is a predictable reactive model with precise updates and minimal framework overhead.
import { createComponent, html } from "udodi";
export const Basic = createComponent({
state() {
return { count: 0 };
},
computed: {
double(ctx) {
return ctx.count * 2;
},
},
methods: {
increment() {
this.count++;
},
},
template: html`
<button @on="click=increment">
<span @text="double"></span>
</button>
`,
});Components keep state, behavior, and templates together, while a small directive set connects them to the DOM. You describe the interface; Udodi handles the reactive wiring without adding unnecessary machinery.
The result is a component model that stays small enough to reason about in full, yet complete enough to build real interfaces without reaching for unnecessary extra libraries or hidden runtime layers.
import { createQueryPool } from "udodi";
const pool = createQueryPool({
worker: {
enabled: true,
computeWorkers: 2,
},
});
pool.registerModule("processBuffer", {
url: new URL("./workers/process-buffer.js", import.meta.url).href,
});
const processed = pool.query("processed", {
module: "processBuffer",
});
await processed.fetch({
input: arrayBuffer,
transfer: true,
});
// Result is available reactively
// through processed.dataQuery Pool manages asynchronous queries, mutations, caching, invalidation, and request state while keeping server data isolated from your component and template model.
For expensive work, queries can execute modules in Web Workers, keeping CPU-intensive tasks off the UI thread. Results return through reactive query state, and large payloads can be transferred without unnecessary copying.
A small reactive core combined with the primitives needed to build real interfaces.
Track dependencies where changes occur and update only the affected parts of the interface.
Explore Reactivity →Build interfaces with HTML and a small, predictable directive DSL.
Explore Templates →Organize state, behavior, lifecycle, templates, and styles around reusable component boundaries.
Explore Components →Whether you are evaluating Udodi or building your first application, these guides provide the quickest path into the framework.
Install Udodi and learn about the available distribution formats.
02Build a small reactive application and see the core workflow in practice.
03Understand how state, behavior, templates, and styles work together.
04Learn how to organize an Udodi application as it grows.
Move from the reactive core to application-level primitives and then into the runtime architecture.
The foundation of every Udodi application.
Built-in primitives for common application concerns.
Understand the runtime beneath the API.
Start with the guides when learning Udodi. Move to the API reference when you need exact details about a specific capability.
Supported by the community
Sponsors help keep Udodi independent and support continued work on its core, documentation, testing, performance, and developer experience.
Interested in supporting Udodi?
Become a sponsor →