Simple Client Router

window.addEventListener('click', async (event) => {
  // 1. Intercept link click
  if (!(event.target instanceof HTMLAnchorElement)) {
    return;
  }
  event.preventDefault();

  // 2. Load new document..
  const res = await fetch(event.target.href);
  const html = await res.text();
  const parser = new DOMParser();
  const newDocument = parser.parseFromString(html, "text/html");

  // 3. ..then render it
  document.title = newDocument.title;
  document.body = newDocument.body;
});
A simplified snippet of the actual source code.

It's fairly easy to write a custom client-side router. This site uses one; it looks something like

You can also do things like support history navigation and use the (experimental) View Transitions API for smooth transitions.

If the experimental Navigation API is ever released, it could make this even easier, since it consolidates all navigation events under one API.