---
title: "useLocalStorage – State Hook Usage & Examples"
description: "useLocalStorage is a React hook that binds state to a localStorage key — a useState-like tuple with SSR safety, custom serializers, and cross-tab sync."
canonical: https://reactuse.com/state/uselocalstorage/
---

# useLocalStorage

React side-effect hook that manages a single `localStorage` key

`useLocalStorage` binds a React state to a `localStorage` key. It returns a `[value, setValue]` tuple similar to `useState`. The value is read from storage on mount and written back whenever you call `setValue`. Setting the value to `null` removes the key. Custom serializers can be provided for non-string data types, and the hook listens for cross-tab `storage` events by default so that changes in one tab are reflected in others.

### When to Use

- Persisting user preferences (theme, language, layout) across page reloads
- Caching form drafts or application state so users can resume where they left off
- Sharing simple state between browser tabs via the `storage` event

### Notes

- **Persistence**: Data survives page reloads and browser restarts. Use `useSessionStorage` if you only need data for the current session.
- **Cross-tab & same-tab sync**: Every component bound to the same key stays in sync — within the current tab (always on, no reload) and across other tabs (via the `storage` event). `listenToStorageChanges: false` disables only the cross-tab listener; same-tab sync stays active.
- **Custom serialization**: For objects or non-string values, provide `serializer.read` and `serializer.write` functions in the options. The default behavior uses JSON serialization for objects and raw strings for string values.
- See also `useSessionStorage` for session-scoped storage and `useCookie` for cookie-based persistence.

## Usage

```tsx live
function Demo() {
  // bind string
  const [value, setValue] = useLocalStorage("my-key", "key");
  
  // bind object with custom serializer
  const [myObj, setMyObj] = useLocalStorage(
    "myObj",
    {
      name: "test",
    },
    {
      serializer: {
        read: (val) => {
          console.log("read", val);
          return JSON.parse(val);
        },
        write: (val) => {
          console.log("write", val);
          return JSON.stringify(val);
        },
      },
    }
  );

  return (
    <div>
      <div>
        <h3>String Value</h3>
        <div>Value: {value}</div>
        <button onClick={() => setValue("bar")}>Set to "bar"</button>
        <button onClick={() => setValue("baz")}>Set to "baz"</button>
        <button onClick={() => setValue(null)}>Remove</button>
      </div>
      
      <div style={{ marginTop: "20px" }}>
        <h3>Object Value</h3>
        <div>Object: {JSON.stringify(myObj)}</div>
        <button onClick={() => setMyObj({ name: "updated" })}>
          Update Object
        </button>
        <button onClick={() => setMyObj({ name: "test", count: 1 })}>
          Add Property
        </button>
        <button onClick={() => setMyObj(null)}>Remove Object</button>
      </div>
    </div>
  );
};

```

## Same-tab sync

Two components bound to the same key stay in sync within the tab — not just across tabs. Click a button in one panel and the other updates immediately, no reload:

```tsx live noInline
function StoragePanel({ label }) {
  const [value, setValue] = useLocalStorage("shared-demo-key", "A");
  return (
    <div
      style={{
        border: "1px solid var(--sl-color-gray-5, #ccc)",
        borderRadius: 6,
        padding: 12,
        marginBottom: 8,
      }}
    >
      <strong>{label}</strong> reads: <code>{String(value ?? "(empty)")}</code>
      <div style={{ display: "flex", gap: 8, marginTop: 8 }}>
        <button onClick={() => setValue("A")}>Set A</button>
        <button onClick={() => setValue("B")}>Set B</button>
        <button onClick={() => setValue(null)}>Clear</button>
      </div>
    </div>
  );
}

function Demo() {
  return (
    <div>
      <p>Click a button in one panel — the other updates in the same tab:</p>
      <StoragePanel label="Component A" />
      <StoragePanel label="Component B" />
    </div>
  );
}

render(<Demo />);
```

%%API%%