> [Agent navigation index](/llms.txt)

# Bind browser storage to components

Define schema-validated storage keys and bind local or session storage reactively to Preact and React components.

Storage is persisted client state. For in-memory coordination across Preact island roots on one page,
use [stores](/docs/stores) instead.

## Define keys once

Use the framework-owned Zod export and colocate reusable keys with the feature that owns them:

```ts
import { createStorageKey } from "brix/storage";
import { z } from "brix/zod";

export const themeKey = createStorageKey("theme", z.enum(["light", "dark"]));
export const profileKey = createStorageKey(
  "profile",
  z.object({ displayName: z.string(), visits: z.number().int().nonnegative() }),
);

```

A `StorageKey` is the plain `{ key, schema }` definition. Reuse it rather than repeating a string and
schema or spreading the definition. Reads, writes, and hooks also accept an inline `(key, schema)`
pair, but a schema is never optional. Removal accepts either a storage key or a string because no
value needs validation.

Choose stable, application-specific key names. Schema changes must tolerate data written by an older
application version or deliberately treat it as missing.

## Use reactive hooks

```tsx
"use island";

import { useLocalStorage } from "brix/hooks";
import { themeKey } from "./storage-keys.ts";

export function ThemePicker() {
  const theme = useLocalStorage(themeKey);

  return (
    <select
      value={theme.value ?? "light"}
      onChange={(event) => {
        const value = event.currentTarget.value;
        if (value === "light" || value === "dark") theme.set(value);
      }}
    >
      <option value="light">Light</option>
      <option value="dark">Dark</option>
    </select>
  );
}

```

`useLocalStorage` and `useSessionStorage` return:

- `value`, the parsed schema output or `null` when absent, invalid, or unavailable.
- `set(value)`, a typed write that validates and updates reactive state after persistence succeeds.
- `remove()`, which removes the item and updates subscribers.

Hooks for the same storage object and key synchronize within the current document, including changes
made through Brix raw helpers. Local-storage hooks also consume browser `storage` events, so another
tab's write re-renders subscribers. Session storage is tab-scoped and does not synchronize across
tabs.

For an app-specific `Storage` implementation, use `useStorage(customStorage, storageKey)` from the
matching Preact or React binding.

Continue with [use typed browser storage helpers](/docs/storage-helpers).
