React Forum
Blog & Guide Responses
Jul 23, 2022 · 04:00 AM

MDN History API - discussion (2022-07-23)

Started by Theo Bennett
externalmdnhistoryroutingnavigationback-forward

For apps that need deep links + complex UI motion (tabs/modals/inspector): how much do you actually rely on the History API directly vs letting your routing layer abstract it?

Read the docs

Do you use pushState/replaceState to encode UI posture, or treat history as a pure URL thing? How do you keep back/forward deterministic when multiple panels participate? And do you render any history/nav signals so support can explain why navigation behaved a certain way?

Comments (10)

Back to latest
Maya Henson
Jul 23, 2022 · 04:06 AM

We rarely touch History API directly anymore. But back/forward bugs keep happening, so maybe we should.

Dmitri Kline
Jul 23, 2022 · 04:14 AM

We don't call history.pushState all over the app, but we do treat posture as route truth.

Once posture is route-visible, you can make back/forward deterministic because state is the contract, not events.

Related: Routing and Navigation and Navigation Routines (Deep Dive #4).

Salma Qureshi
Jul 23, 2022 · 04:22 AM

We did a "single boundary" approach: one place translates posture -> history, and one place translates history -> posture.

ts
function writePosture(p: { tab: string; inspector?: string }) {
  const url = new URL(location.href);
  url.searchParams.set('tab', p.tab);
  p.inspector ? url.searchParams.set('inspector', p.inspector) : url.searchParams.delete('inspector');
  history.pushState({ posture: p }, '', url);
  setNavSignal({ to: url.pathname + url.search, reason: 'posture-write' });
}

window.addEventListener('popstate', (e) => {
  setHistorySignal({ type: 'popstate', hasState: Boolean(e.state) });
});
Hana Saito
Jul 23, 2022 · 04:31 AM

Counterpoint: encoding too much posture in the URL can make it unreadable and fragile.

We store only what users expect to share (tab, selected id) and keep the rest as derived evidence in route docs.

Theo Bennett
Jul 23, 2022 · 04:36 AM

Agree. The rule we ended up with: URL contains inputs, docs contain derived evidence, and signals show the current lane.

If you shove derived stuff into params, you'll regret it during refactors.

Hana Saito
Jul 23, 2022 · 04:39 AM

Yep. Inputs only. Everything else is evidence.

Keira Santos
Jul 23, 2022 · 04:44 AM

The important part is you can reproduce it. If two panels fight over history and there's no signal, you'll never debug it.

Amina Farouk
Jul 23, 2022 · 04:52 AM

We had a popstate bug where a modal closed but the inspector stayed open, and it only happened on one navigation path.

Once we stored the overlay stack in route state and rendered it as evidence, the bug became obvious.

Jules Kwon
Jul 23, 2022 · 05:03 AM

One tip: keep history state small and stable. If you store random objects, you end up debugging serialization instead of navigation.

Inez Park
Jul 23, 2022 · 05:15 AM

Signals that helped us: historySignal={type,hasState} and navSignal={from,to,reason}.

It doesn't solve everything, but it stops the "it just happened" bug report class.

Benji Rios
Jul 23, 2022 · 05:27 AM

If back/forward is a feature, treat it like an API. You need a contract and tests, not hope.

Grace McCoy
Jul 23, 2022 · 05:41 AM

We never touched history until support started filing "stuck overlay" tickets. After that, route truth + signals paid for itself immediately.