The React state library that contains no state.
import { useDomState } from 'stateless-dataos'
const manifest = {
filters: { selector: '[data-filter]', read: 'data:filter' },
search: { selector: '#search', read: 'value' },
}
function App() {
const state = useDomState(manifest) // ← that's it
return <YourApp state={state} />
}No useState. No Redux. No Zustand. No signals.
No state synchronization bugs — ever.
The DOM is the state. You just read it.
This is the official React implementation of DATAOS — the architecture behind multicardz (1M+ cards, sub-100ms interactions).
Built on domx-dataos — the canonical DATAOS implementation for DOM state collection and observation.
- < 1 KB gzipped (plus domx)
- Full TypeScript
- Works with Next.js, SSR, htmx, everything
- Mathematically impossible to have sync bugs
- Read shortcuts:
'value','checked','text','data:name','attr:name'
stateless-dataos complements, rather than competes with, libraries like TanStack Query, SWR, or React Query:
| Library | Purpose | State Source |
|---|---|---|
| stateless-dataos | DOM/UI state | HTML elements |
| TanStack Query | Server/API state | Database endpoints |
Use together for complete state management:
function TodoApp() {
// Server state (TanStack Query)
const { data: todos } = useQuery({
queryKey: ['todos'],
queryFn: fetchTodos
})
// UI state (stateless-dataos)
const { filter, search } = useDomState({
filter: { selector: '[data-filter]', read: 'data:filter' },
search: { selector: '#search', read: 'value' }
})
// Combine both
const filteredTodos = todos?.filter(todo =>
todo.text.includes(search) &&
(!filter || todo.status === filter)
)
}npm install stateless-dataosimport { useDomState, useDomValue, useDomArray, useDomMap } from 'stateless-dataos'
// Basic DOM state reading with shortcuts
const manifest = {
username: { selector: '#username', read: 'value' },
isLoggedIn: { selector: '[data-user]', read: el => !!el.dataset.user }
}
const state = useDomState(manifest)
// Two-way binding helper
const [value, setValue] = useDomValue('#input', 'value')
// Array extraction with shortcuts
const items = useDomArray('[data-item]', 'text')
// Map extraction with shortcuts
const map = useDomMap('[data-entry]', 'data:key', 'data:value')stateless uses domx-dataos read shortcuts:
| Shortcut | What it reads |
|---|---|
'value' |
el.value (form inputs) |
'checked' |
el.checked (checkboxes) |
'text' |
el.textContent |
'data:name' |
el.dataset.name |
'attr:name' |
el.getAttribute('name') |
(el) => ... |
Custom function |
Reads state directly from the DOM using a manifest of selectors and read shortcuts.
Parameters:
manifest: Object mapping keys to{ selector: string, read: string | (el: Element) => any }
Returns: Object with extracted values. Single elements return their value, multiple elements return arrays, missing elements return null.
Two-way binding helper for form inputs.
Parameters:
selector: CSS selector for the elementattribute: Attribute to read/write (defaults to 'value')
Returns: Tuple of [currentValue, setValueFunction]
Extracts an array of values from multiple DOM elements.
useDomMap<T>(selector: string, keyRead: string | Reader<string>, valueRead: string | Reader<T>): Map<string, T>
Extracts a Map from DOM elements with key-value pairs.
Since the DOM is rebuilt on page refresh, UI state is lost. Use the Cache-and-Replay Pattern:
// Before API calls, cache state to localStorage
async function fetchData(filters) {
localStorage.setItem('lastFilters', JSON.stringify(filters))
// ... fetch
}
// On page load, restore and replay
function initialize() {
const cached = localStorage.getItem('lastFilters')
if (cached) {
const filters = JSON.parse(cached)
restoreDomState(filters) // Move DOM elements to cached positions
fetchData(filters) // Replay the API call
}
}This doesn't violate DATAOS principles—we persist state across sessions, not during them. On restore, we immediately re-derive from the corrected DOM.
- domx-dataos — The canonical DATAOS implementation. stateless uses domx-dataos internally.
- DATAOS — The architecture and book behind this approach.
- multicardz — Spatial data platform built with DATAOS.
See CONTRIBUTING.md for details.
Every other React state library is lying to you. They all create a second copy of state in JavaScript that must be kept in sync with the DOM.
stateless-dataos refuses to lie.
There is no second copy. There is no sync. There is only the DOM.
You have been writing DATAOS apps all along — you just didn't know it yet.
stateless-dataos makes it official.
Made by @adamzwasserman Powered by DATAOS and domx-dataos