Storage
@granit/storage provides a typed storage factory for localStorage and sessionStorage
with automatic dd: key prefixing and custom serialization.
@granit/react-storage wraps this into a useStorage hook that synchronizes component
state with the browser storage via useSyncExternalStore, including cross-tab updates.
Peer dependencies: react ^19
Package structure
Section titled “Package structure”Directory@granit/storage/ TypedStorage factory with key prefixing (framework-agnostic)
- @granit/react-storage useStorage hook with cross-tab sync
| Package | Role | Depends on |
|---|---|---|
@granit/storage | createStorage, TypedStorage, StorageOptions | — |
@granit/react-storage | useStorage hook | @granit/storage, react |
import { useStorage } from '@granit/react-storage';
function Sidebar() { const [open, setOpen] = useStorage('sidebar-open', false); return <nav data-open={open}>...</nav>;}import { createStorage } from '@granit/storage';
const themeStorage = createStorage<'light' | 'dark'>('theme');themeStorage.set('dark'); // writes to localStorage key "dd:theme"themeStorage.get(); // returns 'dark'themeStorage.remove(); // removes "dd:theme"TypeScript SDK
Section titled “TypeScript SDK”interface StorageOptions<T> { serialize?: (value: T) => string; // default: JSON.stringify deserialize?: (raw: string) => T; // default: JSON.parse storage?: 'local' | 'session'; // default: 'local'}
interface TypedStorage<T> { get(): T | null; set(value: T): void; remove(): void; readonly key: string; // prefixed key (e.g. "dd:theme")}createStorage<T>(key, options?)
Section titled “createStorage<T>(key, options?)”Creates a typed storage accessor. All keys are automatically prefixed with dd: to
avoid collisions with third-party libraries.
function createStorage<T>(key: string, options?: StorageOptions<T>): TypedStorage<T>;React bindings
Section titled “React bindings”useStorage<T>(key, defaultValue, options?)
Section titled “useStorage<T>(key, defaultValue, options?)”React hook that synchronizes component state with browser storage.
function useStorage<T>( key: string, defaultValue: T, options?: StorageOptions<T>): [T, (value: T) => void];- Uses
useSyncExternalStorefor tear-free reads - Cross-tab synchronization via the native
storageevent - Maintains referential stability through internal caching
- Keys are automatically prefixed with
dd:
Key prefixing
Section titled “Key prefixing”All keys are prefixed with dd: (Digital Dynamics) to avoid collisions:
| Input key | Actual storage key |
|---|---|
theme | dd:theme |
sidebar-open | dd:sidebar-open |
locale | dd:locale |
Public API summary
Section titled “Public API summary”| Category | Key exports | Package |
|---|---|---|
| Types | TypedStorage<T>, StorageOptions<T> | @granit/storage |
| Factory | createStorage() | @granit/storage |
| React hook | useStorage() | @granit/react-storage |
See also
Section titled “See also”- Granit.BlobStorage module — .NET server-side blob storage (S3-compatible)
- Localization — Uses
dd:localevia this storage system - Settings — Server-side cascaded settings complement client-side storage