Join our Discord Community

React useLocalStorage Hook

React useLocalStorage hook for persistent state. Automatic serialization with cross-tab synchronization and SSR support using TypeScript for Next.js apps.

localStorage hook not working?

Join our Discord community for help from other developers.


Ever tried to persist user preferences across page reloads and ended up wrestling with localStorage APIs, JSON serialization bugs, and cross-tab sync issues? You know the drill—manually saving to localStorage on every state change, forgetting to parse JSON back to objects, dealing with storage quota errors. This free open source React useLocalStorage custom hook handles all that persistence complexity so you can focus on building stateful features instead of debugging storage edge cases in your React applications.

useLocalStorage showcase

Persistent state that survives page reloads and syncs across tabs:

Loading component...

This free open source React hook simplifies browser storage with TypeScript support for modern JavaScript applications. Whether you're building user preferences, form drafts, or session data in your Next.js projects, this React hook keeps your state persistent and synchronized.

Installation

npx shadcn@latest add https://www.shadcn.io/registry/use-local-storage.json
npx shadcn@latest add https://www.shadcn.io/registry/use-local-storage.json
pnpm dlx shadcn@latest add https://www.shadcn.io/registry/use-local-storage.json
bunx shadcn@latest add https://www.shadcn.io/registry/use-local-storage.json

Why most localStorage implementations suck

Look, you could keep calling localStorage.setItem and JSON.stringify everywhere. But then you hit the storage complexity—serialization errors with undefined values, quota exceeded exceptions, cross-tab synchronization headaches, SSR hydration mismatches in React applications.

Most developers manually manage localStorage calls with fragmented try-catch blocks that don't handle all edge cases in TypeScript components. Or they forget about cross-tab synchronization and wonder why user changes in one tab don't appear in others. Some skip SSR considerations entirely and get hydration mismatches with flashing content in Next.js projects.

This React hook provides a useState-like API that automatically handles serialization, error recovery, and cross-tab updates in JavaScript applications. One interface for all your localStorage needs.

Plus it handles all the edge cases—graceful fallbacks when localStorage is disabled, proper SSR initialization, automatic event listening for cross-tab sync in React development. No more scattered try-catch blocks.

This free open source React hook manages persistent storage while you focus on building features. Whether you're creating React applications, Next.js dashboards, or TypeScript components, reliable state persistence keeps your JavaScript development smooth.

Features

  • Persistent state that survives page reloads and browser sessions in React applications
  • Automatic serialization with JSON serialization/deserialization by default in TypeScript components
  • Cross-tab synchronization syncs changes across browser tabs automatically in Next.js projects
  • Custom serializers support for dates, complex objects, and custom types in JavaScript development
  • SSR compatible with optional initialization for server-side rendering in React frameworks
  • Type safety with full TypeScript support and proper generics for modern applications
  • Error handling with graceful fallbacks for localStorage errors
  • Free open source designed for modern React development workflows

When you'll actually use this

Real talk—this isn't for every piece of state in React applications. Regular useState works fine for temporary UI state. But when you need data to persist across sessions or sync across tabs, this React hook handles the complexity in Next.js projects.

Perfect for:

  • User preferences - Theme settings, language choices, and UI configurations built with TypeScript
  • Form drafts - Save progress on long forms to prevent data loss using React patterns
  • Shopping carts - Persist cart items across browser sessions in JavaScript applications
  • Session data - User settings and temporary data that should survive refreshes in React components
  • Feature flags - Client-side toggles that persist across visits in Next.js applications
  • Recently viewed - Track user interactions and browsing history using TypeScript safety

API Reference

useLocalStorage

useLocalStorage<T>(key: string, initialValue: T | (() => T), options?: UseLocalStorageOptions<T>): [T, (value: T | ((prev: T) => T)) => void, () => void]
ParameterTypeDescription
keystringThe key under which the value will be stored in localStorage
initialValueT | (() => T)The initial value or a function that returns the initial value
optionsUseLocalStorageOptions<T>Optional configuration for serialization and behavior

UseLocalStorageOptions

PropertyTypeDefaultDescription
serializer(value: T) => stringJSON.stringifyFunction to serialize the value before storing
deserializer(value: string) => TJSON.parseFunction to deserialize the stored value
initializeWithValuebooleantrueWhether to initialize with stored value (set to false for SSR)

Return Value

Returns a tuple with:

  • value: The current stored value
  • setValue: Function to update the value (same API as useState)
  • removeValue: Function to remove the key from localStorage and reset to initial value

Common gotchas

Storage quota limits apply: Browsers limit localStorage size (usually 5-10MB) in React applications. The React hook handles quota exceeded errors gracefully but won't prevent them.

Cross-tab sync has slight delays: Storage events fire when other tabs change values, but there's a small delay in TypeScript components. Don't rely on instant synchronization.

SSR requires careful initialization: Use initializeWithValue: false for SSR to prevent hydration mismatches in Next.js projects, then handle the loading state appropriately.

JSON serialization has limitations: Dates become strings, undefined values are dropped, functions can't be serialized in JavaScript applications. Use custom serializers for complex types.

Storage availability checks: Always handle cases where localStorage might be disabled by browser settings or privacy mode in React frameworks.

Key naming consistency: Use consistent key naming patterns across your application to avoid conflicts and enable easier debugging in TypeScript projects.

Questions you might have