synced-storage
v1.3.2
Published
A small, framework‑agnostic utility for syncing cookies, localStorage, and sessionStorage with application state.
Downloads
276
Maintainers
Readme
Synced Storage
Battle-tested, framework-agnostic utility for syncing cookies, localStorage, and sessionStorage with application state. Ships with first-class React bindings — adapters for Svelte, SolidJS, and Vue are on the way.
Features
- Unified API — read, write, and subscribe to cookies and web storage through the same interface
- SSR-ready — hydrate cookie values on the server; the client picks up seamlessly
- Cross-tab & same-tab sync — storage changes propagate across tabs via native
StorageEventand within the same tab via synthetic events - Key expiration — set a
Dateon any storage key and it auto-resets when it expires - Functional setState —
setState(prev => ...)always receives the latest value, no stale closures - Portable core — zero React dependency; use the core with any framework
- Tiny footprint — single production dependency (
universal-cookie) - Tree-shakeable — ESM + CJS with
sideEffects: false - Fully typed — written in TypeScript with exported declarations
Installation
npm install synced-storageCore Usage (Any Framework)
Use the storage core directly — no React required.
import { CookieClient } from "synced-storage/core";
const client = new CookieClient();
const store = client.getOrCreateStore("theme", "light");
store.subscribe((value) => {
console.log(`theme changed to ${value}`);
});
store.setItem("dark");Quick Start (React)
1. Wrap your app with SyncedStorageProvider
import { cookies } from "next/headers";
import { SyncedStorageProvider } from "synced-storage/react";
export default async function RootLayout({ children }) {
return (
<html>
<body>
{/* ssrCookies is optional — only needed in SSR environments */}
<SyncedStorageProvider ssrCookies={(await cookies()).getAll()}>
{children}
</SyncedStorageProvider>
</body>
</html>
);
}2. Cookie state
import { useCookieState } from "synced-storage/react";
function PersonDetails() {
const [person, setPerson] = useCookieState("person", {
name: "Jane",
age: 30,
});
return (
<div>
<p>
{person.name}, {person.age}
</p>
<button
onClick={() => setPerson((prev) => ({ ...prev, age: prev.age + 1 }))}
>
+1
</button>
</div>
);
}3. Local / session storage
import { useStorageState } from "synced-storage/react";
type Theme = "light" | "dark";
function ThemeToggle() {
const [theme, setTheme] = useStorageState<Theme>("theme", "light", {
strategy: "localStorage", // or "sessionStorage"
});
return (
<div>
<p>{theme}</p>
<button
onClick={() =>
setTheme((prev) => (prev === "light" ? "dark" : "light"))
}
>
Toggle theme
</button>
</div>
);
}Exports
| Entry point | Contents |
| ---------------------- | -------------------------------------------------------------- |
| synced-storage | Same as synced-storage/core |
| synced-storage/core | CookieClient, StorageClient, CookieStore, StorageStore |
| synced-storage/react | useCookieState, useStorageState, SyncedStorageProvider |
Examples
| Example | Stack | What it shows |
| --------------------------------------- | --------------------- | -------------------------------------------------------------------------------------------------- |
| examples/nextjs/ | Next.js 16 + React | SSR cookie hydration, useCookieState, useStorageState |
| examples/plain/ | Vanilla JS (no build) | CookieClient, StorageClient — open index.html to navigate; 3 pages, CDN import via importmap |
License
MIT
