DOM As The Authority On State

domx

Stop syncing JavaScript state with DOM state.
Read from the DOM when you need it. Write to the DOM when it changes.
No Redux. No MobX. No useState. Just the DOM.

<1KB
Gzipped
7
Functions
1
Observer
0
Dependencies

The DATAOS Way

Define a manifest that maps state labels to DOM selectors. domx reads and writes state through that manifest. The DOM is always the source of truth.

Define Your Manifest

Map state labels to DOM locations

const manifest = {
  searchQuery: { selector: '#search', read: 'value', write: 'value' },
  sortDir: { selector: '[data-sort]', read: 'attr:data-sort-dir' },
  filters: { selector: '.filter.active', read: 'data:filter' }
};

Use Pure Functions

Collect, apply, observe

// Read state from DOM
const state = domx.collect(manifest);
// { searchQuery: "hello", sortDir: "asc", filters: ["active"] }

// Write state to DOM
domx.apply(manifest, { searchQuery: "world" });

// Watch for changes
domx.observe(manifest, (state) => {
  console.log('State changed:', state);
});

Seven Pure Functions

collect()

Read state from DOM based on manifest

apply()

Write state to DOM based on manifest

observe()

Watch DOM for state changes

on()

Low-level mutation subscription

send()

Fetch with state caching

replay()

Restore state on page refresh

clearCache()

Clear cached request

Why domx?

Simple

Pure Functions

No classes, no instances, no this. Just functions that do one thing.

Declarative

Manifest Pattern

Define state-to-DOM mapping once. Read and write through the manifest.

Tiny

<1KB Gzipped

Smaller than a tweet. Zero dependencies. Ships in milliseconds.

Efficient

Single Observer

One MutationObserver for all state watching. Batched callbacks via rAF.

Resilient

Page Refresh Recovery

Cache state before requests. Replay on refresh. Never lose user work.

Compatible

htmx Integration

First-class htmx extension. Auto-stuffs state into requests.

htmx Integration

domx includes an htmx extension for seamless hypermedia integration. State is automatically collected and sent with requests.

<body hx-ext="domx" dx-manifest="manifest" dx-cache="true">
  <input id="search" type="text">
  <button hx-post="/api/search" hx-trigger="click">
    Search
  </button>
</body>

<!-- State auto-collected and sent with every htmx request -->
<!-- Cached to localStorage for page refresh recovery -->

Get Started

npm
npm install domx

Or via CDN:

<script src="https://unpkg.com/domx"></script>