DEV Community

Ajdin Imsirovic
Ajdin Imsirovic

Posted 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

Quick note before we dive in: You can use any frontend library or framework as the rendering/view layer. Combine it with @everystate/view, or use it exclusively. Want React for rendering and the EveryState ecosystem for state, CSS, routing, and testing? That works. @everystate/react provides usePath and useIntent hooks so React components can subscribe to the store. EveryState doesn't replace your view layer - it gives everything around it a unified address space.


What does it look like?

Here's a complete counter app:

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

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

const { cleanup } = 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, decrement }
);
Enter fullscreen mode Exit fullscreen mode
// increment.js
export function increment(store) {
  store.set('count', store.get('count') + 1);
}
Enter fullscreen mode Exit fullscreen mode

That's it. No JSX. No build step. No bundler. Open the HTML file, and it runs.

The CSS? It's co-located right on the view nodes. createApp auto-extracts css: {} to css.{class}.{prop} paths in the store, and the style engine reactively applies them to the DOM via CSSOM.

The handlers? store is auto-injected as the first argument. Write a function, pass it by name. No manual wiring.


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/renderer Direct-binding renderer. bind-*, set, each attributes. Zero
@everystate/router SPA routing as state. Routes are just store paths. Zero
@everystate/perf Performance monitoring overlay. Zero
@everystate/test Event-sequence testing. createEventTest. Zero
@everystate/react React adapter. usePath, useIntent. Zero (react is peer)

Total external dependencies across the entire ecosystem: zero. Every package is a native ES module. No bundler. No transpiler.


The Core Idea: Dot-Path Addressable Everything

The dot-path is the central concept. It's a universal address for everything in the application - 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, your data lives in one system (useState, ref, signals), your styles live in another (CSS files, Tailwind, styled-components), your routes in another (react-router, vue-router), your tests in another (Jest, Vitest). Each has its own API, its own mental model, its own debugging tools.

In EveryState, every concern uses the same three methods. When you learn how @everystate/core works, you already know how @everystate/css, @everystate/router, and @everystate/test work - they all just read and write paths in the same store.


How Does It Compare?

I've been building EveryState as an alternative to the frameworks I've been using (and teaching) for years. Here's an honest comparison across the landscape. I'll highlight what each tool does well and where EveryState offers a different trade-off.

vs React

Dimension React EveryState
Rendering Virtual DOM diffing, component re-renders Surgical O(1) updates via path subscriptions
State useState, useReducer, useContext, plus external libs One store, dot-paths
Build step Required (JSX compilation) None (native ES modules)
CSS Many options: CSS Modules, styled-components, Tailwind css.{selector}.{prop} in the store, reactive
Testing Jest + RTL + act() + mock providers createEventTest - assert on state, no DOM needed
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 is powerful and well-understood, but it creates a class of optimization work (React.memo, useMemo, useCallback, dependency arrays) that EveryState sidesteps entirely - subscriptions only fire for the exact path that changed.

React's strengths: Massive ecosystem, huge hiring pool, battle-tested at enormous scale (Meta, Netflix, Airbnb), mature SSR via Next.js, React Native for mobile. React is the industry standard for good reason.

EveryState's different trade-off: No re-renders to optimize. No hook rules to remember. No build step. The entire update model is "path changed -> subscriber fires." That's it.

vs Vue

Dimension Vue EveryState
Reactivity Proxy-based, component-scoped Path-based subscriptions, global store
Templates .vue SFCs with v-if, v-for, v-bind Plain JS objects
Build step Practically required for .vue files None
State sharing provide/inject, Pinia One store - everything shared by default

Vue's Composition API and EveryState are aiming at the same target: fine-grained reactivity. Vue layers it on top of a component model and template compiler. EveryState starts from the store and derives everything else from it.

Vue's strengths: Excellent documentation, approachable learning curve, Vite (born in Vue-land), growing enterprise adoption, well-designed ecosystem (Pinia, Vue Router).

vs Angular

Dimension Angular EveryState
Architecture Modules, components, services, DI, decorators, RxJS Store + view spec + handlers
Build step Mandatory (CLI, TypeScript, zone.js) None
Bundle ~65KB+ gz minimum ~4KB core

Angular is a comprehensive, opinionated platform. It brings a lot of structure out of the box - which is valuable for large teams that need strong conventions. Its recent adoption of signals (Angular 17+) moves it toward the same fine-grained reactivity model that EveryState uses.

Angular's strengths: Enterprise adoption, strong conventions reduce decision fatigue, Google backing, TypeScript-first, comprehensive CLI tooling.

EveryState's different trade-off: Minimal API surface (get, set, subscribe) instead of a large framework vocabulary. Convention over configuration, but the conventions are just path naming.

vs Svelte

Dimension Svelte EveryState
Approach Compiler turns .svelte into optimized vanilla JS Already vanilla JS - no compiler needed
Build step Required (Svelte compiler) None
Runtime size Near-zero (compiled away) ~4KB (nothing to compile)

Svelte is the closest in philosophy to EveryState. Both care deeply about small output and developer experience. Both reject the virtual DOM. The key difference is the mechanism: Svelte achieves its goals through a compiler that transforms custom syntax into optimized JS. EveryState achieves them through a simpler architecture where the code you write is the code that runs.

Svelte 5's runes ($state, $derived, $effect) work inside .svelte files. EveryState's reactivity works in any .js file, in the browser console, in Node.js - anywhere JavaScript runs.

Svelte's strengths: SvelteKit is a mature full-stack framework. Compiled output is highly optimized. Template syntax feels natural to HTML developers. Growing community and adoption.

vs Solid

Solid is architecturally the most similar to EveryState in the mainstream landscape. Both use fine-grained reactivity, both skip the virtual DOM, both achieve O(1) updates.

The key difference is the address model. Solid's signals are reactive values, but they don't have addresses - you need a reference to a specific signal to read it. EveryState's dot-paths ARE addresses. Any part of the system can access any other part just by knowing the path string. This is what enables cross-cutting features like store.subscribe('*', fn) for activity logging, or tests that assert on CSS paths.

Solid's strengths: SolidStart for SSR, JSX familiarity for React developers, excellent performance benchmarks, growing community with corporate backing.

vs Elm

Elm pioneered the unidirectional data flow (Model-Update-View) that inspired Redux and much of the React ecosystem. EveryState's architecture shares that same DNA. The difference: Elm requires learning a custom ML-family language, while EveryState is plain JavaScript.

Elm's "no runtime exceptions" guarantee is genuinely impressive. EveryState takes a different approach with runtime contracts via @everystate/test - live assertions that run continuously and report violations in real-time, inside the same store.

vs jQuery

jQuery and EveryState share a quality that's easy to overlook: no build step, direct platform access. Drop a script tag and go.

The difference: jQuery is imperative DOM manipulation (the DOM is the source of truth). EveryState is declarative state projection (the store is the source of truth, the DOM is a projection of it). You get jQuery's low-friction setup without the maintenance challenges of imperative DOM code at scale.

vs Preact

Preact proves that React's ~45KB isn't necessary for the same API. But Preact deliberately inherits React's architectural decisions: virtual DOM, component re-renders, hook rules. It's a lighter React. EveryState isn't trying to be a lighter anything - it's a different approach to the same problem.


vs State Management Libraries

This is where the comparison gets most interesting, because @everystate/core IS a state management library - but it's also the foundation for everything else in the ecosystem.

vs Redux

Dimension Redux EveryState
Mutations Action objects with type strings store.set('path', value) - the path is the action type
State 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

Redux got the big idea right: single source of truth with predictable state flow. EveryState keeps that insight and strips the ceremony. The dot-path IS the action type. set IS the reducer. get IS the selector.

Redux's time-travel DevTools are a genuinely great feature. EveryState has snapshot()/restore() on the roadmap for similar capability.

vs Zustand, Jotai, Valtio, Pinia, MobX

  • Zustand is excellent - probably the best React state library. But it's React-bound: useStore is a hook, subscriptions trigger component re-renders. EveryState's store feeds everything: view, CSS, routes, tests.

  • Jotai takes a bottom-up atomic approach, similar in concept to paths. The key difference: Jotai atoms are scattered across files with no central registry. EveryState paths form a single enumerable tree.

  • Valtio uses Proxies for transparent reactivity (state.count++ just works). EveryState requires explicit store.set() calls - one more line, but every mutation is visible and greppable in the codebase.

  • Pinia is well-designed for Vue. EveryState is framework-agnostic - it works with Vue, React (via @everystate/react), or vanilla JS.

  • MobX tracks dependencies automatically, which is powerful but creates dependency graphs that can be hard to debug. EveryState's subscriptions are explicit - the debugging surface is flat.

vs XState

XState and EveryState solve different problems. XState models processes (state machines with transitions and guards). EveryState models data (values at paths). They're complementary. You could use XState to manage complex flows and write results to an EveryState store.


vs Meta-Frameworks (Next.js, Nuxt, Remix)

EveryState does not have a meta-framework equivalent. No "EveryState-Next." This is the biggest ecosystem gap.

Feature Meta-frameworks EveryState
Routing File-based routing @everystate/router - routes are store paths
SSR Server components, streaming serialize(resolveTree(...)) produces HTML. No server pipeline yet.
Deployment Platform-specific (Vercel, Cloudflare) Any static file server

For SPAs - dashboards, admin panels, internal tools, creative tools, editors - SSR is often unnecessary, and EveryState's zero-build deployment to any CDN is a genuine advantage. For SEO-critical marketing sites, the meta-frameworks are the right choice today.

Honorable mentions

  • HTMX - Server-driven (hypermedia) vs EveryState's client-driven (state). Different philosophies, complementary use cases.
  • Alpine.js - Sprinkle reactivity into HTML. Similar spirit to @everystate/renderer. Alpine scopes state to DOM elements; EveryState centralizes it.
  • Astro - Content-first with islands of interactivity. Each island could be a createApp call - a natural fit worth exploring.
  • Qwik - "Resumability" requires serializable state. EveryState's state is already fully serializable, making a similar strategy architecturally possible.
  • Tailwind - Utility classes in HTML vs utility properties in the store. Both avoid writing CSS files. EveryState's approach is reactive (change a value, style updates); Tailwind's is static.

Ease of Use

Framework "Hello World" Files needed Build step
React (Vite) ~10 lines ~12 generated Yes
Angular ~20 lines ~20 generated Yes
Svelte ~5 lines ~8 generated Yes
EveryState ~10 lines 2 (HTML + JS) No

The initial setup is comparable. Where EveryState differs is how complexity scales. In most frameworks, growing the app means adding new libraries for state, CSS, routing, testing - each with its own API and learning curve. In EveryState, you add more paths to the same store. The API stays get, set, subscribe. The mental model stays flat.


Learning Curve

To be productive in React, you typically need to understand: JSX, components, props, hooks (useState, useEffect, useRef, useCallback, useMemo, useContext), hook rules, effect cleanup, dependency arrays, React.memo, Context API, a state management library, a CSS solution, a router, a testing library, build tool configuration. That's roughly 15+ concepts before you're comfortable.

To be productive in EveryState:

  1. createEveryState(initialState) - create a store
  2. store.get('path') - read a value
  3. store.set('path', value) - write a value
  4. store.subscribe('path', fn) - react to changes
  5. Wildcards: store.subscribe('path.*', fn)
  6. View specs: objects with tag, text, class, children, css, onClick
  7. createApp(store, el, viewSpec, handlers) - mount an app
  8. Handlers receive store as their first argument

8 concepts. And when you add CSS, routing, or testing capabilities, you don't learn new APIs - they all use the same get/set/subscribe on the same store.


Developer Experience

Here's what daily development looks like with EveryState v1.1.0:

Define a view node - structure, content, behavior, and style in one place:

{ tag: 'button', class: 'btn', text: 'Click me', onClick: 'handleClick',
  css: { padding: '8px 16px', borderRadius: '4px', cursor: 'pointer' } }
Enter fullscreen mode Exit fullscreen mode

Write a handler - a plain function, testable in isolation:

export function handleClick(store, event) {
  store.set('clicked', true);
}
Enter fullscreen mode Exit fullscreen mode

Test it - no DOM, no browser, no mocking:

const t = createEventTest({ clicked: false });
t.trigger('clicked', true);
t.assertPath('clicked', true);
Enter fullscreen mode Exit fullscreen mode

Derive reactive values - plain JavaScript:

store.subscribe('count', () => {
  const count = store.get('count');
  store.set('css.value.color', count > 0 ? 'green' : count < 0 ? 'red' : 'gray');
});
Enter fullscreen mode Exit fullscreen mode

What's still on the roadmap

  • IDE integration - No autocomplete for dot-paths yet. Path strings don't give the editor type information the way typed props do. This is the biggest DX gap.
  • Browser DevTools - React DevTools and Vue DevTools are mature. EveryState has a performance overlay, but not a full state tree inspector extension. Coming.
  • Hot Module Replacement - Currently save-and-refresh. Live reload is planned.

Scalability and Maintainability

store.get('path') is O(1). store.set('path', value) is O(1) plus the cost of notifying subscribers for that specific path. Paths provide natural namespacing:

user.profile.name
products.list.0.name
cart.items.0.productId
view.nodes.v42.text
css.card.borderRadius
route.current
Enter fullscreen mode Exit fullscreen mode

The path naming convention IS the architecture. No "modules," no "slices" - just paths with conventional prefixes.

For maintainability, the difference is in dependency surface. A typical React project maintains: application code + the dependency tree + the build pipeline + TypeScript config + linting config for JSX. In EveryState, you maintain: application code + @everystate/core (which has zero transitive dependencies). The surface area for "something broke because a dependency updated" is dramatically smaller.

Does it scale to large teams? This is an honest open question. EveryState's simplicity means fewer concepts to miscommunicate. But it also means teams need their own conventions for path organization. Frameworks with more structure (Angular, for instance) enforce those conventions for you. EveryState trusts developers to define their own.


The 5-Year Question

This is where I think EveryState makes its strongest case.

A brief history of frontend "best practices"

Year The recommendation Status in 2026
2014 Angular 1 + Grunt + Bower Dead. Complete rewrite (Angular 2+ is a different framework).
2016 React + Create React App CRA abandoned. Meta recommends Next.js.
2017 Vue 2 + Vuex + Vue CLI Vue 2 EOL. Vuex replaced by Pinia. Vue CLI replaced by Vite.
2018 React + Redux + styled-components Redux declining. styled-components declining.
2021 Svelte 4 + SvelteKit Svelte 5 rewrote the reactivity model.
2023 Next.js App Router + React Server Components Significant community pushback. API still evolving.

The pattern is clear: frameworks churn, build tools churn, state libraries churn. The things that DON'T churn are web platform APIs: document.createElement, element.addEventListener, fetch, ES modules, CSS properties. These have been stable for years, some for decades.

What EveryState is built on

  • ES modules - Part of the JavaScript language spec since 2015. Supported in all browsers.
  • DOM APIs - createElement, textContent, addEventListener - stable since the 2000s.
  • CSSOM - CSSStyleSheet.insertRule - standardized, stable.
  • Plain objects and strings - { tag: 'div', text: 'hello' }. No custom syntax.
  • Import maps - Browser-native module resolution. No bundler needed.
  • Zero dependencies - Nothing external can break.

An EveryState app written today will run in any browser that supports ES modules - that's every modern browser, and has been since 2018. There is nothing to update, nothing to migrate, nothing that can be deprecated out from under you.

Compare that to a React app written in 2021: Create React App is abandoned, Webpack config may need updating, React 17 to 18 to 19 involves migration work, class components to hooks is an ongoing refactor, Redux to Zustand is a rewrite, styled-components to Tailwind is a rewrite.

EveryState aims for code that you write once and that keeps running.


Five Principles

These are the design principles behind every decision in the EveryState ecosystem:

1. Total Backwards Compatibility

Once the API stabilizes: open-closed principle. get, set, subscribe are the foundation and they're not changing. New capabilities come as additions (snapshot(), derived(), new packages), not as modifications to existing APIs. The goal is a plugins-only architecture from that point forward.

2. As Close to the Platform as Possible

EveryState uses: ES modules, DOM APIs, CSSOM, plain JavaScript, import maps.

It does not use: Webpack, TypeScript, JSX, Babel, PostCSS. No configuration files. No node_modules with hundreds of megabytes of transitive dependencies. Save a file, refresh the browser. That's the dev loop.

3. No Magic

Every operation is explicit and traceable:

  • store.set('count', 5) - the value at count becomes 5. Nothing else happens.
  • store.subscribe('count', fn) - fn is called when count changes. Nothing else.
  • onClick: 'increment' - the handler named increment is called on click. Nothing else.

No Proxy traps, no compiler transforms, no automatic dependency tracking, no monkey-patching of browser APIs. The source of @everystate/core is ~300 lines of readable JavaScript.

4. As Simple as Possible, but Not Simpler

EveryState includes wildcards, setMany, queryClient, forEach, and classIf because real applications need them. It does not include a virtual DOM, lifecycle hooks, dependency injection, or a template language because this architecture doesn't need them.

5. Dot-Paths Are a Superpower

store.subscribe('*', fn);                  // complete activity log of the entire app
store.set('css.card.borderRadius', '8px'); // CSS is just state
store.subscribe('count', () => {           // live runtime contracts
  store.set('tests.countIsNumber', typeof store.get('count') === 'number');
});
Enter fullscreen mode Exit fullscreen mode

The dot-path turns the entire application into an addressable, observable, serializable structure. Data, view, CSS, routes, tests - all in one place, all with the same API.


Current Limitations

Every tool has trade-offs. Here's where EveryState is today:

  • No SSR pipeline - The building blocks exist (serialize produces HTML from state), but there's no server-side rendering framework, hydration strategy, or streaming. For SEO-heavy sites, use a meta-framework.
  • No TypeScript - By design. Dot-paths are strings; the IDE doesn't know what's at 'user.profile.name'. Runtime contracts via @everystate/test provide safety at a different layer.
  • Young ecosystem - No component marketplace, no DataGrid, no DatePicker. You build with primitives or integrate vanilla JS libraries.
  • Early-stage adoption - React has Meta, Netflix, Airbnb. EveryState has a growing collection of examples and a thorough test suite. It's proving itself, but it's early.
  • DevTools in progress - Performance overlay exists. A full browser extension with state tree inspection is on the roadmap.

Try It

Option A: npm (recommended)

mkdir my-app && cd my-app
npm init -y
npm install @everystate/core
Enter fullscreen mode Exit fullscreen mode

Create two files:

index.html

<!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": "./node_modules/@everystate/core/index.js",
      "@everystate/core/everyState.js": "./node_modules/@everystate/core/everyState.js",
      "@everystate/core/queryClient.js": "./node_modules/@everystate/core/queryClient.js"
    }
  }
  </script>
  <script type="module" src="app.js"></script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

app.js

import { createEveryState } from '@everystate/core';

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

store.subscribe('count', () => {
  document.getElementById('display').textContent = store.get('count');
});

document.getElementById('inc').addEventListener('click', () => {
  store.set('count', store.get('count') + 1);
});

document.getElementById('dec').addEventListener('click', () => {
  store.set('count', store.get('count') - 1);
});
Enter fullscreen mode Exit fullscreen mode

Serve it with any static file server (npx serve ., python3 -m http.server, VS Code Live Server - anything). Open the page. That's a running EveryState app. No build step, no bundler, no config files.

Option B: CDN (zero install)

If you want to skip npm entirely, esm.sh bundles the package into a single browser-ready module:

<script type="importmap">
{
  "imports": {
    "@everystate/core": "https://esm.sh/@everystate/core@1.0.6"
  }
}
</script>
<script type="module" src="app.js"></script>
Enter fullscreen mode Exit fullscreen mode

Same app.js as above. No npm, no node_modules. Just an HTML file, a JS file, and a CDN URL.

What's next after the counter?

  • Add @everystate/view for declarative view specs and createApp
  • Add @everystate/css for reactive styling via css.* paths
  • Add @everystate/router for SPA routing as state
  • Add @everystate/test for live runtime contracts

Each package uses the same store, the same get/set/subscribe. No new mental models.


Current versions: @everystate/core 1.0.6 | @everystate/view 1.1.0 | @everystate/css 1.0.10

If you found this interesting, check out the npm package or star the repo. I'd love to hear what you think in the comments - what would you build with addressable state?

Top comments (0)