Every state gets a URL

Tabs, filters and pages live in the URL: reload, share and Back work.

Guillermo Rauch7 Principles of Rich Web Applications
Consider, for example, the typical "infinite pagination scenario". The typical way it's implemented involves capturing the click with JavaScript, requesting some data / HTML, injecting it. Making the history.pushState or replaceState call is an optional step, unfortunately not taken by many.
rauchg.com · 2014Read article ↗
Guillermo Rauch7 Principles of Rich Web Applications
And this is why I use the word "break". With the simpler model the web proposed initially, this situation was not in the picture. Every state transition relied on a URL change.
rauchg.com · 2014Read article ↗

Both demos simulate a browser; this page's real URL never changes.

Reload, share, go Back

Pick a tab, a status and Load more, then Reload or Share.

State in memoryBad
Try Reload, Share or Back
State in the URLGood
Try Reload, Share or Back
"use client";
function useSetParams() {
  const router = useRouter();
  const params = useSearchParams();
  return (patch, mode = "push") => {
    const next = new URLSearchParams(params);
    for (const [k, v] of Object.entries(patch)) v ? next.set(k, v) : next.delete(k);
    router[mode](`?${next}`, { scroll: false });
  };
}

set({ tab: "preview", page: null });   // push: Back returns here
set({ page: page + 1 });               // push: "Load more" is a state too
set({ q: e.target.value }, "replace"); // typing: one entry, not ten

Push views, replace typing

Type a branch name, switch tab, then press Back.

Push every keystrokeBad
Back presses to leave: 1
Replace while typingGood
Back presses to leave: 1

Why it matters, pros and cons

Why it matters

Reload, share and Back all read the URL. State that never reaches it is state they can't bring back.

Pros

  • Reload and shared links land on the exact same view.
  • Back steps through views instead of out of the app.
  • Support can paste a link to what the customer sees.

Cons

  • Open menus and hover states don't belong in history.
  • Pushing every keystroke floods Back; replace instead.
  • Huge filter sets make ugly URLs; save them under an id.