Back should be instant

Show the page you left from cache, at the scroll you left it.

Guillermo Rauch7 Principles of Rich Web Applications
Without the browser managing URLs and history for us, new challenges emerge. Make sure not to break expectations related to scrolling. Keep your own caches for fast feedback.
rauchg.com · 2014Read article ↗
Guillermo Rauch7 Principles of Rich Web Applications
This is akin to considering the back button an application-level button and applying principle 2: act immediately on user input. The key is that you can now decide how to cache the previous page and render it instantly.
rauchg.com · 2014Read article ↗
Guillermo Rauch@rauchg
Probably the most interactive, generative and dynamic application I've ever seen is v0.dev – full stack @nextjs. Featuring: … ◾︎ Instant back / forward navigations
Jan 19, 2025View on X ↗

Demo 2 follows the essay: restore state that only matters while moving through history.

Open a post, then go Back

Scroll the feed, open a post, then press Back.

Refetch on BackBad
Not back yet
Cached, scroll keptGood
Not back yet
// Leaving: keep the list, and write where the reader was into the entry
cache.set(location.pathname, listData);
history.replaceState({ ...history.state, scrollY: feed.scrollTop }, "");
history.pushState(null, "", `/posts/${id}`);

// Back: paint from cache, restore scroll, then revalidate quietly
addEventListener("popstate", ({ state }) => {
  render(cache.get(location.pathname));   // 0ms, no spinner
  feed.scrollTop = state?.scrollY ?? 0;
  revalidate(location.pathname);          // update rows in place
});

Restore what was open

Expand two threads, open a profile, then press Back.

Remounts with defaultsBad
0 threads open
State in the entryGood
0 threads open
// Expanded replies matter only when coming Back: keep them in the history entry
function toggle(id) {
  open.has(id) ? open.delete(id) : open.add(id);
  history.replaceState({ ...history.state, open: [...open] }, "");
}
const open = new Set(history.state?.open ?? []);

Why it matters, pros and cons

Why it matters

Back promises the page you left. A refetch breaks it twice: a wait, then the wrong spot.

Pros

  • Back costs 0ms: the list is already in memory.
  • The reader lands on the post they opened, not the top.
  • Revalidating after paint still gets fresh data.

Cons

  • Caches cost memory; keep a few screens and evict.
  • Prices and stock can't be stale; revalidate those first.
  • Multi-page sites get this from the bfcache; don't block it.