Only what
changes.
When state changes, Zidom knows which DOM bindings depend on it. Those bindings update. Everything else stays where it is.
One change. Precise updates.
TRACE 001Change the signal above. Bound text changes; unrelated content stays put.
The right node. The right time.
Nothing more to update.
Change something.
Watch the result.
These are not video demos or animated mockups. Each preview runs a real Zidom component and exposes its source.
Loading interactive demo…
import { signal, computed } from '@zidomjs/core';export default function CounterDemo() { const count = signal(0); const doubled = computed(() => count.value * 2); return ( <div className="example-card"> <p>Click to update a single bound text node.</p> <div className="demo-number">{count}</div> <p> Computed double: <strong>{doubled}</strong> </p> <div className="demo-actions"> <button onClick={() => count.value--}>−</button> <button onClick={() => (count.value = 0)}>Reset</button> <button onClick={() => count.value++}>+</button> </div> </div> );}Loading interactive demo…
import { signal } from '@zidomjs/core';export default function ConditionalDemo() { const connected = signal(false); return ( <div className="example-card"> <button onClick={() => (connected.value = !connected.value)}> Toggle connection </button> <div className="demo-output"> {() => connected.value ? ( <p role="status">Connected. This branch is mounted.</p> ) : ( <p role="status">Disconnected. The previous branch was disposed.</p> )} </div> </div> );}Loading interactive demo…
import { signal } from '@zidomjs/core';import { For } from '@zidomjs/dom';interface Task { id: number; name: string;}export default function ListsDemo() { const tasks = signal<Task[]>([ { id: 1, name: 'Read the guide' }, { id: 2, name: 'Try a signal' }, { id: 3, name: 'Build with Zidom' } ]); const nextId = signal(4); return ( <div className="example-card"> <p>Stable keys keep row DOM identity when the order changes.</p> <ul className="demo-list"> <For each={tasks} by={task => task.id}> {(task, index) => ( <li> <span>{() => `${index.value + 1}. ${task.value.name}`}</span> <button aria-label={() => `Remove ${task.value.name}`} onClick={() => { tasks.value = tasks.value.filter( item => item.id !== task.value.id ); }} > Remove </button> </li> )} </For> </ul> <div className="demo-actions"> <button onClick={() => (tasks.value = [...tasks.value].reverse())}> Reverse </button> <button onClick={() => { const id = nextId.value++; tasks.value = [...tasks.value, { id, name: `New task ${id}` }]; }} > Add task </button> </div> </div> );}Less repeated work.
More intention.
A reactive binding updates when its dependency changes. Zidom does not need to rerun a whole component setup for every value update. That is the architectural design; measured release sizes are shown separately.
Explore benchmarks and methodology ↗Minified ES2022 public-API measurement, not complete application downloads or a competitor ranking. Measurement scope ↗
Subscribe precisely
Signals notify the bindings that read them, not a whole virtual UI description.
Keep what exists
Keyed lists can preserve DOM identity, focus and existing row nodes when reordered.
Test the actual work
Browser DOM correctness is checked in a 1,000-row harness; fair rankings require more application-level evidence.
Small ideas.
Powerful together.
Start with a minimal rendering core. Add routing, data, forms and shared state as your application needs them.
Fine-grained signals
A changed value updates its dependent DOM bindings, not a whole tree.
Direct rendering
JSX creates browser nodes; reactive values keep them in sync.
Composable tools
Router, queries, stores, forms and DI are each available independently.
Optional compiler
Use explicit bindings now; explore conservative TSX compilation when ready.
Start from working code.
Buttons, inputs, forms and navigation with live previews and copyable TSX/CSS. No mysterious library of screenshots.
Write the state.
Bind the result.
Pass a signal straight into JSX. When its value changes, the bound DOM text updates without rerunning component setup.
Read the getting-started guide ↗import { signal } from '@zidomjs/core';import { mount } from '@zidomjs/dom';function Counter() { const count = signal(0); return <button onClick={() => count.value++}> Count: {count} </button>;}mount(() => <Counter />, document.querySelector('#app')!);Begin at the source.
Read the model, explore a working demo, then ship a component that is yours to keep.
A personal name.
A deliberate idea.
Zi comes from Zidane. DOM is the Document Object Model. Zidom joins a personal dedication to a belief in more precise interfaces.
The story behind Zidom ↗