React Forum
Blog & Guide Responses
Feb 12, 2023 · 04:00 AM

MDN History API - discussion (2023-02-12)

Started by Keira Santos
externalhistorynavigationpopstateroutingreplaceStatecontractsevidence

MDN's History API page is a good reminder that the browser isn't your router; it's a primitive you build contracts on top of. Once you know how pushState, replaceState, and back/forward actually behave, it's easier to design calm URLs and make route docs replayable rather than relying on hidden component state.

Read the docs

Do you treat URL changes as intent commands or as a representation of state? What do you log/render as evidence so back/forward bugs are diagnosable without guesswork? How do you decide what belongs in URL vs route doc when you have lots of UI motion (overlays, panels)?

Comments (12)

Back to latest
Marisol Vega
Feb 15, 2023 · 03:15 PM

URL is where; route docs are what.

That split made back/forward coherent because replay happens from an explicit model, not from hidden component state.

Dmitri Kline
Feb 18, 2023 · 06:06 AM

We log history transitions as contract lines and include the reason so changes aren't mysterious:

txt
[tips] history pushState url=/threads/42 reason=nav:click
[tips] history popstate url=/threads reason=back
[tips] history replaceState url=/search?q=react&sort=recent reason=normalize:query

Those three lines answer most "why did the URL change" questions.

Keira Santos
Mar 01, 2023 · 03:03 AM

Counterpoint: if you keep too much out of the URL, sharing becomes frustrating.

We treat URL keys as share-worthy user meaning (category, sort, q). Everything else stays in the route doc and is replayable, not shareable.

Amina Farouk
Mar 05, 2023 · 05:05 AM

That distinction helped our team too.

Share-worthy keys in URL; behavior-worthy keys in docs. When we blurred that line, the app got fragile fast.

Grace McCoy
Mar 18, 2023 · 06:18 PM

Back/forward bugs often turned out to be "panel state isn't replayable" bugs.

Once we made panel state a route-doc key (typed), back/forward became predictable.

Jasper Nguyen
Apr 06, 2023 · 06:06 AM

Long-form: history is an API surface whether you want it or not.

If you use replaceState to normalize, that's a product decision and it must have a reason you can explain.

Logging and evidence are governance tools as much as debugging tools.

Nina Kapoor
Apr 18, 2023 · 06:18 PM

We also render data-history-action=push|replace|pop as evidence.

It helped support diagnose why users can't "go back" (replaceState chains are a common culprit).

Camille Duarte
May 10, 2023 · 10:10 AM

Counterpoint: history logging can get noisy in apps with lots of param churn.

We log only push/replace/pop, plus a compact route-doc summary, not every param tweak.

Owen Price
Jun 01, 2023 · 06:06 AM

A practical tool: log the route-doc replay on popstate. It makes it clear whether the bug is in history or in your state replay:

txt
[tips] replay routeDoc panel=list selection=null reason=popstate
Benji Rios
Jul 14, 2023 · 02:14 PM

Long-form counterpoint: teams often treat history state as storage, which creates hidden, unversioned contracts.

If you need persistence, use a real store/vault. History is navigation.

Lina Ortega
Aug 19, 2023 · 07:19 PM

Docs tie-in: the routing docs here are basically a set of guardrails for using history primitives safely.

Related: Routing and Navigation and The App Router Mindset.

Salma Qureshi
Oct 15, 2023 · 03:15 PM

We found that the most valuable evidence isn't the URL string—it's the contract summary.

When the summary is visible, history bugs stop being mystical.

Tomas Rivera
Dec 31, 2023 · 09:09 AM

If you implement history normalization, make it idempotent and make it logged.

If normalization runs twice, the URL shouldn't keep changing. That's a contract you can actually trust.