DEV Community

Cover image for What If Everything in Your UI Had an Address?
Ajdin Imsirovic
Ajdin Imsirovic

Posted on • Edited on

What If Everything in Your UI Had an Address?

What if your application data, your DOM structure, your CSS, your routes, and your tests were all just... paths in the same store?

count                     -> application data
view.nodes.v0.tag         -> the DOM structure
css.body.background       -> a CSS property
route.current             -> the current URL
tests.passed              -> live contract results
Enter fullscreen mode Exit fullscreen mode

All readable with store.get(path). All writable with store.set(path, value). All reactive with store.subscribe(path, fn).

Three methods. One mental model. That's EveryState.

@everystate/core on npm · GitHub


A server-state library in 30 lines

Here's the argument made concrete. React Query is ~39KB minified and introduces its own cache, its own query key system, its own subscription mechanism, its own status tracking. It exists because server state is treated as a separate category from client state.

In EveryState, it isn't. Server state is just state that arrives asynchronously, stored at query.${key} paths. The core store already has async handling via setAsync, which means a full server-state library collapses to this:

export const createQueryClient = (store) => ({
  query(key, fetcher)  { return store.setAsync(`query.${key}`, fetcher); },
  subscribe(key, cb)   { return store.subscribe(`query.${key}.data`, cb); },
  getData(key)         { return store.get(`query.${key}.data`); },
  getStatus(key)       { return store.get(`query.${key}.status`); },
  cancel(key)          { store.cancel(`query.${key}`); },
  invalidate(key) {
    const p = `query.${key}`;
    store.set(`${p}.data`, null);
    store.set(`${p}.status`, 'idle');
    store.set(`${p}.error`, null);
  },
});
Enter fullscreen mode Exit fullscreen mode

The hard problems React Query solves — caching, deduplication, reactive reads, status tracking — don't exist in this world, because the store primitive already handles them. The library isn't clever. It's small because the primitive makes it small.

This is the pattern across the ecosystem.


The ecosystem

Package What it does External deps
@everystate/core The store. get, set, subscribe, wildcards, async. Zero
@everystate/view View-as-state. Normalize, flatten, project. createApp. Zero
@everystate/css Reactive CSSOM. Design tokens, typed CSS. Zero
@everystate/router SPA routing as state. Routes are just store paths. Zero
@everystate/test Event-sequence testing that generates TypeScript types. Zero
@everystate/types Typed dot-path autocomplete. Zero
@everystate/query Server state as paths. The 30-line example above. Zero
@everystate/react React adapter. usePath, useIntent. Zero (react is peer)

Each package is a native ES module. No bundler. No transpiler. Total external dependency count across the whole ecosystem: zero.


What does it look like?

A complete counter app:

import { createEveryState } from '@everystate/core';
import { createApp } from '@everystate/view/app';
import { createStyleEngine } from '@everystate/css';

const store = createEveryState({ count: 0 });
createStyleEngine(store);

createApp(store, '#app',
  {
    tag: 'div', class: 'counter', css: { textAlign: 'center' },
    children: [
      { tag: 'h1', text: 'Count: {count}' },
      { tag: 'button', text: '-', onClick: 'decrement' },
      { tag: 'span', text: '{count}', class: 'value',
        css: { fontSize: '3rem', fontWeight: '700' } },
      { tag: 'button', text: '+', onClick: 'increment' },
    ]
  },
  {
    increment: (store) => store.set('count', store.get('count') + 1),
    decrement: (store) => store.set('count', store.get('count') - 1),
  }
);
Enter fullscreen mode Exit fullscreen mode

No JSX. No build step. No bundler. Open an HTML file with an import map, and it runs.

createApp does two things implicitly: it extracts css: {} blocks into css.{class}.{prop} paths (so the style engine can apply them reactively), and it passes store as the first argument to handlers. Everything else is explicit store reads and writes.


The core idea: dot-path addressable everything

The dot-path is a universal address — like a file path in Unix or a URL on the web.

store.get('css.body.background')           // read a CSS value
store.set('css.body.background', '#000')   // change it reactively
store.subscribe('css.*', fn)               // watch all CSS changes
store.subscribe('*', fn)                   // watch everything
Enter fullscreen mode Exit fullscreen mode

In most frameworks, data lives in one system (useState, signals, stores), styles in another (CSS files, styled-components), routes in another (react-router), tests in another (Jest). Each has its own API, its own mental model, its own debugging story.

In EveryState, all of these are paths in the same store. When you've learned get, set, and subscribe, you already know how to use @everystate/css, @everystate/router, and @everystate/test — they're just conventions over the same three methods.


How it compares to React

Dimension React EveryState
Rendering Virtual DOM diffing, component re-renders Subscriptions fire for the exact path that changed
State useState, useReducer, useContext, plus external libs One store, dot-paths
Build step Required (JSX compilation) None (native ES modules)
CSS Multiple external libraries css.{selector}.{prop} in the store, reactive
Testing Jest + RTL + act() + mock providers Assert on state paths, no DOM
Bundle ~45KB gz (react + react-dom), plus tooling ~4KB gz (core only)

React's component model is built on running functions and diffing their output. This creates a class of optimization work — React.memo, useMemo, useCallback, dependency arrays — that EveryState sidesteps because subscriptions only fire for the exact path that changed. No re-renders to optimize; there are no renders to speak of.

React has things EveryState doesn't: a massive hiring pool, battle-tested scale at Meta and Netflix, mature SSR via Next.js, React Native for mobile. It is the industry standard for good reason.

EveryState offers a different trade-off: the entire update model is "path changed, subscriber fires." No hook rules. No build step. The code you write is the code that runs.


How it compares to Redux

Redux got the foundational idea right: single source of truth with predictable state flow. EveryState keeps that insight and strips the ceremony.

Redux EveryState
Mutations Action objects with type strings store.set('path', value) — the path is the action type
Updates Reducer functions return new state set writes directly
Boilerplate Types, creators, reducers, selectors, slices store.set('count', 1)
DevTools Time-travel, action log, state diff subscribe('*', fn) + perf overlay

The dot-path IS the action type. set IS the reducer. get IS the selector. Redux-style state flow without the ceremony.


Quick comparisons to the rest of the landscape

  • Vue / Pinia: Fine-grained reactivity layered on a component model and template compiler. EveryState starts from the store and derives everything else.
  • Angular: Comprehensive platform with strong conventions. Its signals adoption (v17+) moves toward the same fine-grained reactivity, but the framework surface is much larger.
  • Svelte: Closest philosophical match. Both reject the virtual DOM. Svelte achieves it through a compiler; EveryState through a simpler architecture with no compiler.
  • Solid: Most similar architecturally. Both use fine-grained reactivity. The key difference is the address model: Solid's signals are values, EveryState's paths are addresses. Any part of the system can read or write any other part just by knowing the path string.
  • Zustand / Jotai / Valtio / MobX: Excellent state libraries, each framework-bound or React-bound in practice. EveryState's store feeds everything — view, CSS, routes, tests — not just components.
  • XState: Models processes (state machines). EveryState models data (values at paths). Complementary. You can drive an EveryState store from XState transitions.
  • HTMX / Alpine / Astro / Qwik / Tailwind: Different philosophies, some of which compose cleanly with EveryState (an Astro island could be a createApp call). Worth a longer post of its own.
  • Meta-frameworks (Next, Nuxt, Remix): EveryState has no equivalent. This is the biggest ecosystem gap. For SEO-critical marketing sites, the meta-frameworks are the right choice today. For SPAs — dashboards, internal tools, editors — EveryState's zero-build deployment to any CDN is a genuine advantage.

Types: behavior-first instead of declaration-first

Most libraries type through declarations: you write interface User { ... } and hope the code matches. EveryState types through behavior.

@everystate/test records runtime type assertions as tests run:

const t = createEventTest({ user: { name: 'Ada', age: 36 } });
t.assertShape('user', { name: 'string', age: 'number' });
Enter fullscreen mode Exit fullscreen mode

The assertions verify behavior and record themselves into a type table. A separate tool — @everystate/types — generates TypeScript .d.ts declarations from that table, giving you full path-level autocomplete in your IDE at compile time, zero runtime cost.

The types come from verified behavior rather than aspirational interfaces. You can still hand-write types if you prefer — @everystate/types supports both flows — but the default path produces types that are guaranteed to match runtime.

This is a different approach to TypeScript, not an absence of it.


What it's built on

Frameworks churn. The web platform doesn't.

Angular 1 was the 2014 standard; it's dead. Create React App was the 2016 standard; it's abandoned. Vue 2 + Vuex was the 2017 standard; both are replaced. styled-components, CRA, Webpack — all in decline or migration mode. Next.js App Router is still fighting community adoption three years in.

What hasn't churned: document.createElement, addEventListener, fetch, ES modules, CSS properties. Some of these are two decades old.

EveryState is built on exactly those primitives: ES modules, DOM APIs, CSSOM, plain objects, import maps. No Webpack, no Babel, no PostCSS, no JSX. Nothing to migrate away from.

An EveryState app written today will run in any browser that supports ES modules — which is every modern browser since 2018 — and will keep running, because the APIs it uses are the APIs the browser ships.


Current limitations

  • No SSR framework. serialize(resolveTree(...)) produces HTML from state, so the primitive is there, but there's no hydration strategy, streaming, or server pipeline. For SEO-critical sites, use Next or Nuxt.
  • Early adoption. React has Meta. EveryState has six months of public npm presence, a working ecosystem, and a growing set of examples. It's proving itself, but it's early.
  • No DevTools extension yet. Performance overlay exists. Full state tree inspector is on the roadmap.
  • Community conventions. The simplicity means teams need their own conventions for path organization. Frameworks with more structure enforce those conventions for you. EveryState trusts developers to define their own — which is a strength for small teams and an open question for large ones. If you're using EveryState at team scale, I want to hear from you.

Try it

Fastest path — CDN, no install:

<!DOCTYPE html>
<html>
<head><title>EveryState</title></head>
<body>
  <h1 id="display">0</h1>
  <button id="inc">+</button>
  <button id="dec">-</button>

  <script type="importmap">
  { "imports": { "@everystate/core": "https://esm.sh/@everystate/core@1.0.6" } }
  </script>

  <script type="module">
    import { createEveryState } from '@everystate/core';

    const store = createEveryState({ count: 0 });
    const display = document.getElementById('display');

    store.subscribe('count', () => { display.textContent = store.get('count'); });
    document.getElementById('inc').onclick = () => store.set('count', store.get('count') + 1);
    document.getElementById('dec').onclick = () => store.set('count', store.get('count') - 1);
  </script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

One file. Open it in a browser, or python3 -m http.server, or npx serve. That's a running EveryState app.

For the full ecosystem (@everystate/view, /css, /router, /test), see the docs and the npm package.


Code for all eight packages is on npm under @everystate.

If you've built something with path-addressable state — or if you think this approach is wrong — I'd genuinely like to hear why. The paradigm claim is that frontend's hardest problems collapse when state is the only primitive and everything else is a subscriber. The eight libraries are the evidence. If there's a case where the pattern breaks, I want to know.

Top comments (0)