useSessionStorageLoading saved progress…

useSessionStorage

useSessionStorage is useState that survives a reload but not a tab close. It works exactly like useStateconst [value, setValue] = useSessionStorage(key, initial) — but the value is persisted to sessionStorage, which is scoped to a single tab and wiped when that tab closes. It's the right fit for a multi-step form's progress, a scroll position, or a "seen this modal" flag that shouldn't leak into other tabs the way localStorage does.

Implement useSessionStorage(key, initialValue). On first render, read the stored value (or fall back to initialValue). setValue updates React state and writes to sessionStorage, accepting a value or an updater function. If sessionStorage is unavailable (SSR, private mode, quota), degrade gracefully to plain useState behavior instead of throwing.

Signature

function useSessionStorage(key, initialValue) {
  // returns [value, setValue] — like useState, backed by sessionStorage.
}

Examples

const [step, setStep] = useSessionStorage('checkout-step', 1);
setStep(2);               // state updates AND sessionStorage['checkout-step'] = '2'
// reload the tab -> step is 2; close the tab -> gone
const [draft, setDraft] = useSessionStorage('draft', '');
setDraft((d) => d + '!'); // functional updater, like useState

Notes

  • Read on init (lazy) — use a lazy initializer so sessionStorage is read once on mount, not on every render. Parse the stored JSON; fall back to initialValue if the key is absent or the JSON is corrupt.
  • Write on setsetValue must update state and JSON.stringify the value into sessionStorage.
  • Functional updaters — support setValue(prev => next) like useState.
  • No cross-tab event — unlike localStorage, sessionStorage is per-tab, so there's no meaningful cross-tab storage event to subscribe to. That's the one piece useLocalStorage has that this hook doesn't need.
  • Be defensive — wrap storage access in try/catch (private mode, quota, SSR where window is undefined) and fall back gracefully; a failed write must not crash the component.
Loading editor…