Introduction
Type-safe, framework-agnostic library for working with familiar hooks and reactive values
Why?
When using many different libraries for working with utils, I kept running into the same issues:
- No tests
- No way to use the value outside of components
- Poor or missing typing
So I created a library based on shadcn/cli and called it Hookas. But it was React-only and still had the same problem: you couldn't use the data outside of components.
Solution
That's why I built Seitu (word "utils" reversed, with the letter L replaced by E). It's a type-safe, framework-agnostic library for working with familiar hooks. I brought together my experience with TypeScript and different frameworks, so you can use Seitu with React, Vue, Solid, Svelte, or without any framework at all.
Installation via Agents
Using Claude Code, Cursor, or another agent that supports skills? Add Seitu skills, then hand it this prompt to set up primitives for you:
npx skills add letstri/seituInstall and wire up Seitu in this project.
1. Detect my stack (framework(s), server/client split, e.g. React, Vue, Solid,
Svelte, or no framework) and install `seitu` plus the matching framework
binding from https://seitu.letstri.dev/docs.
2. Scan the codebase for state that's currently local/component-only (useState,
ref, signal) but is actually shared, persisted, or derived from browser
APIs, and replace it with the matching Seitu primitive: createStore,
createSchemaStore, createComputed, createWebStorage(Value),
createIndexedDbStorage, createIndexedDbTable, createMediaQuery, createIsOnline, or
createScrollState.
3. Create primitives at module scope (never inside a component/render), and
wire framework components to them with the `useSubscription` hook /
composable / primitive, or the `Subscription` component where render-prop
composition is clearer.
4. Follow the seitu-overview and per-primitive skill references for the
shared get/subscribe/set API, SSR defaults, and common mistakes.Or continue with the manual installation below.
Installation
npm install seituImport from seitu for framework-agnostic core primitives, seitu/web for browser persistence and DOM state, and seitu/react, seitu/vue, seitu/solid, or seitu/svelte for framework bindings.
Create primitives at module scope
Every create* function returns a handle with the same get(), set(), and subscribe() API. Create it once at module scope (or with a factory passed to useSubscription), then share it between components, utilities, and tests.
Examples
Local Storage / Session Storage
One of the painful spots for me was localStorage. I wanted typed storage that I could also use reactively.
With Seitu you get a reactive, typed value that works both inside and outside components:
import { } from 'seitu/web'
import * as from 'zod'
const = ({
: 'localStorage',
: 'count',
: 0,
: .(),
})
.()
.(1)
.( => + 1)
.( => .())In React, subscribe with useSubscription:
'use client'
import { } from 'seitu/web'
import { } from 'seitu/react'
import * as from 'zod'
export default function () {
const = (() => ({
: 'localStorage',
: 'count',
: 0,
: .(),
}))
return <>{}</>
}Ready?
Core primitives
Stores, schema stores, computed values, debounce and throttle. Work everywhere JavaScript runs.
Web primitives
Typed localStorage, sessionStorage, IndexedDB, media queries, scroll state and online status.
React
useSubscription hook and Subscription component for any Seitu handle.
Vue
useSubscription composable that returns a reactive ref.
Solid
Signal-based useSubscription primitive and Subscription component.
Svelte
Rune-friendly useSubscription for Svelte 5.
Last updated on