React Forum
Blog & Guide Responses
Jan 18, 2023 · 04:00 AM

MDN History API - discussion (2023-01-18)

Started by Priya Liao
externalmdnhistorypushstatepopstateroutingevidence

MDN's History API docs are still the best "what actually happens" reference when an app's routing behavior feels off. I'm curious how people apply push/replace/pop semantics in route-first React apps where the URL is a map, route state is the contract, and motion needs to be explainable via evidence.

Read the MDN docs

How do you decide between pushState and replaceState for component-router motion (overlays, tabs, selection)? Do you persist route state into the URL, or treat URL params as a hint that seeds state once? What evidence do you render so "back" behavior is debuggable without watching a video?

Comments (14)

Back to latest
Marisol Vega
Jan 22, 2023 · 10:02 AM

Replace is underrated.

If the user is just changing posture (toggle, filter), replace can keep history meaningful instead of a thousand micro-steps.

Dmitri Kline
Feb 02, 2023 · 06:44 AM

We treat push vs replace as part of the route contract: navigation intent chooses it explicitly.

ts
type NavIntent = { type: 'openOverlay'; overlay: 'share' | 'search'; mode: 'push' | 'replace' };

function applyNav(intent: NavIntent) {
  const url = new URL(location.href);
  url.searchParams.set('overlay', intent.overlay);
  if (intent.mode === 'push') history.pushState({}, '', url);
  else history.replaceState({}, '', url);
}

Then we render data-overlay evidence so back/forward is explainable.

Keira Santos
Feb 14, 2023 · 07:20 PM

Counterpoint: replaceState can surprise users if it hides steps they expected to undo.

We got complaints when a filter change couldn't be backed out because we replaced instead of pushing.

Priya Liao
Feb 17, 2023 · 07:11 AM

Yep, it's a UX choice. We only use replace for ephemeral posture (tab focus, density, panel) and push for user-meaningful changes.

The hard part is agreeing what counts as meaningful.

Grace McCoy
Mar 02, 2023 · 05:33 AM

The best evidence we added was a route ledger that stores {from,to,reason}.

When "back" behaves weird, you can look at the ledger and see what the app thought it was doing.

Jasper Nguyen
Mar 20, 2023 · 12:12 PM

We treat URL params as a hint: parse once, then route state becomes truth, then we re-serialize the parts that are shareable.

That kept us from sprinkling new URLSearchParams() across the codebase.

Nina Kapoor
Apr 07, 2023 · 10:01 PM

A misunderstanding I had early on: I thought popstate should "restore" everything automatically.

In practice, the app needs a route contract that decides what gets restored and what gets re-derived.

Camille Duarte
Apr 24, 2023 · 06:28 AM

We used History API to keep selection shareable (e.g. selectedId=...) but kept volatile state (scroll) local.

If you try to serialize everything, the URL turns into a state dump.

Owen Price
May 13, 2023 · 07:12 PM

Code snippet: a tiny popstate handler that writes evidence instead of silently mutating state:

ts
window.addEventListener('popstate', () => {
  route.write('lastNav', { type: 'pop', at: Date.now(), href: location.href });
});

If you can see lastNav, you stop guessing why the UI changed.

Benji Rios
Jun 02, 2023 · 03:03 AM

Docs tie-in: a lot of this is just routing fundamentals + evidence.

Related: Routing and Navigation and The App Router Mindset.

Lina Ortega
Jun 23, 2023 · 10:40 AM

We also stopped calling things "back button bugs" and started calling them "history contract bugs".

Once it's a contract, you can test it and reason about it.

Amina Farouk
Jul 12, 2023 · 09:55 PM

Counterpoint: ledgers are great until they get noisy.

We only record navigations that change identity (route, selected id, overlay open/close), not every keystroke.

Grace McCoy
Jul 15, 2023 · 08:30 AM

Same. We treat the ledger like audit logs: record the decisions users care about.

The evidence needs to stay readable.

Tomas Rivera
Aug 08, 2023 · 04:12 AM

History API is also where focus/scroll bugs hide.

We ended up rendering data-restored=true when a pop restoration happened so the UI could adapt intentionally.

Sofia Valdez
Sep 01, 2023 · 04:16 PM

If you do replace/push inconsistently across the app, back/forward becomes impossible to predict.

Pick a rule and make it explicit, even if it's a simple one.

Evan Brooks
Oct 10, 2023 · 03:28 AM

MDN is great for the primitive details, but the hard part is deciding which motions deserve a history entry. That's app design.