Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/rijvi-mahmud/shaddy/llms.txt

Use this file to discover all available pages before exploring further.

useLocalStorage is a React hook that provides a useState-style interface for persisting values in the browser’s localStorage. It handles JSON serialization and deserialization automatically, keeps state in sync across multiple tabs via the storage event, and exposes a third tuple element to remove the stored value and reset to the initial state. It accepts custom serializers for complex types like Date objects, an onError callback for graceful failure handling, and an initializeWithValue flag to control server-side rendering behaviour.

Installation

npx shadcn@latest add https://shaddy-docs.vercel.app/r/use-local-storage
useLocalStorage depends on useEventListener. The CLI command above installs both automatically.

Signature

type UseLocalStorageOptions<T> = {
  serializer?:          (value: T) => string
  deserializer?:        (value: string) => T
  initializeWithValue?: boolean
  onError?:             (error: Error, key: string) => void
}

function useLocalStorage<T>(
  key:           string,
  initialValue?: T | (() => T),
  options?:      UseLocalStorageOptions<T>
): [T, Dispatch<SetStateAction<T>>, () => void]

Parameters

key
string
required
The localStorage key to store the value under. Each unique key is an independent storage slot.
initialValue
T | (() => T)
The value (or a factory function returning the value) to use when no entry exists in localStorage for the given key. Defaults to undefined.
options
UseLocalStorageOptions<T>
Optional configuration object.

Return Value

[0] storedValue
T
The current value from localStorage (or initialValue if nothing is stored). Always typed as T.
[1] setValue
Dispatch<SetStateAction<T>>
A setter function with the same API as React’s useState setter. Accepts a new value directly or an updater function (prev: T) => T. Updates both the React state and localStorage atomically.
[2] removeValue
() => void
Removes the item from localStorage and resets the React state to initialValue.

Usage

Persisting a User Preference

import { useLocalStorage } from "@/hooks/use-local-storage"

type Theme = "light" | "dark" | "system"

export function ThemeSelector() {
  const [theme, setTheme, removeTheme] = useLocalStorage<Theme>(
    "app-theme",
    "system"
  )

  return (
    <div>
      <p>Current theme: {theme}</p>

      <button onClick={() => setTheme("light")}>Light</button>
      <button onClick={() => setTheme("dark")}>Dark</button>
      <button onClick={() => setTheme("system")}>System</button>
      <button onClick={removeTheme}>Reset to default</button>
    </div>
  )
}

Persisting a Complex Object

import { useLocalStorage } from "@/hooks/use-local-storage"

type UserSettings = {
  notifications: boolean
  language: string
  fontSize: number
}

const DEFAULT_SETTINGS: UserSettings = {
  notifications: true,
  language: "en",
  fontSize: 16,
}

export function SettingsPanel() {
  const [settings, setSettings] = useLocalStorage<UserSettings>(
    "user-settings",
    DEFAULT_SETTINGS
  )

  return (
    <div>
      <label>
        <input
          type="checkbox"
          checked={settings.notifications}
          onChange={(e) =>
            setSettings((prev) => ({ ...prev, notifications: e.target.checked }))
          }
        />
        Enable notifications
      </label>

      <select
        value={settings.language}
        onChange={(e) =>
          setSettings((prev) => ({ ...prev, language: e.target.value }))
        }
      >
        <option value="en">English</option>
        <option value="fr">Français</option>
        <option value="es">Español</option>
      </select>
    </div>
  )
}

Custom Serialization for Date Objects

import { useLocalStorage } from "@/hooks/use-local-storage"

export function LastVisitTracker() {
  const [lastVisit, setLastVisit] = useLocalStorage<Date | null>(
    "last-visit",
    null,
    {
      serializer:   (date) => (date ? date.toISOString() : ""),
      deserializer: (str)  => (str ? new Date(str) : null),
    }
  )

  const handleVisit = () => setLastVisit(new Date())

  return (
    <div>
      <p>
        Last visit:{" "}
        {lastVisit ? lastVisit.toLocaleString() : "Never"}
      </p>
      <button onClick={handleVisit}>Record visit</button>
    </div>
  )
}

Notes

  • Changes from other browser tabs are detected via the storage event and automatically reflected in the hook’s state, keeping all open tabs in sync.
  • The hook guards against environments where window.localStorage is unavailable (SSR, private browsing that has blocked storage) and calls onError gracefully rather than throwing.
  • The setValue setter accepts an updater function (prev) => next just like useState, making it easy to merge partial updates into object values.
  • If you need session-scoped persistence (cleared when the tab closes), use useSessionStorage instead, which has an identical API.

Build docs developers (and LLMs) love