Skip to Content
HooksuseLocalStorageState

useLocalStorageState

A drop-in useState that persists to localStorage and stays in sync across browser tabs

0

Open this page in a second tab — both stay in sync, and the value survives a reload

import { useLocalStorageState } from 'react-stateful-hooks'; function ThemeToggle() { const [theme, setTheme, resetTheme] = useLocalStorageState('theme', 'light'); return ( <> <button onClick={() => setTheme((t) => (t === 'light' ? 'dark' : 'light'))}> Theme: {theme} </button> <button onClick={resetTheme}>Reset</button> </> ); }

Signature

const [value, setValue, removeValue] = useLocalStorageState<T>( key: string, defaultValue: T, options?: { serializer?: { parse(raw: string): T; stringify(value: T): string }; syncTabs?: boolean; // default: true }, );
ReturnDescription
valueCurrent value (typed as T)
setValueAccepts a value or an updater (prev) => next, like useState
removeValueClears the key from storage and resets state to defaultValue

Behaviour worth knowing

  • SSR-safe — built on useSyncExternalStore, so it returns defaultValue on the server and hydrates without a mismatch, then reads storage on the client
  • Resilient — corrupted JSON or a getItem/setItem failure (quota, private mode) falls back to the default and keeps the in-memory value instead of throwing
  • Cross-tab sync — listens to the storage event and updates state when another tab writes the same key. Disable with { syncTabs: false }. Hooks in the same tab always stay in sync, regardless of this flag
  • Custom serialization — pass a serializer to support Date, Map, BigInt, or a compact wire format
const [since, setSince] = useLocalStorageState('since', new Date(), { serializer: { parse: (raw) => new Date(JSON.parse(raw)), stringify: (value) => JSON.stringify(value.getTime()), }, });
Last updated on