npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

stateless-dataos

v1.0.0

Published

The React state library with zero state — pure DATAOS

Readme

stateless

npm version Build Status License: MIT

The React state library that contains no state.

import { useDomState } from 'stateless'

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.

Features

  • < 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'

Complementary to Server State Libraries

stateless complements, rather than competes with, libraries like TanStack Query, SWR, or React Query:

| Library | Purpose | State Source | |---------|---------|--------------| | stateless | 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)
  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)
  )
}

Install

npm install stateless

Quick Start

import { useDomState, useDomValue, useDomArray, useDomMap } from 'stateless'

// 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')

Read Shortcuts

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 |

API Reference

useDomState<T>(manifest: T): ExtractedState<T>

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.

useDomValue(selector: string, attribute?: string): [string, (value: string) => void]

Two-way binding helper for form inputs.

Parameters:

  • selector: CSS selector for the element
  • attribute: Attribute to read/write (defaults to 'value')

Returns: Tuple of [currentValue, setValueFunction]

useDomArray<T>(selector: string, read: string | Reader<T>): T[]

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.

Handling Browser Refresh

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.

Related Projects

  • 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.

Website

stateless.software


Contributing

See CONTRIBUTING.md for details.


The truth

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 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 makes it official.


Made by @adamzwasserman Powered by DATAOS and domx-dataos