Changing Dom Content

The router knows the URL. Now something has to update the DOM. A switch statement maps routes to view elements, and a single container element holds the current page.

May 1, 20264 min read3 / 4

A URL change triggers nothing by itself. pushState updates the address bar and nothing else. I learned this the hard way: the DOM stays on the previous page until something explicitly swaps it. That something is renderRoute -- a function that maps a path to a view element and puts it on screen.

The Essentials

  1. renderRoute as the view layer: A function that takes a route string and returns the correct page element. The router calls it; it handles the DOM.
  2. Switch statement for routes: The most readable way to map a small set of URL paths to corresponding view elements.
  3. Single container element: One <main> element holds the current page. Navigation clears it and inserts the new page element.
  4. children vs childNodes: children returns only element nodes. childNodes returns all nodes including text nodes and comments. For removing rendered page content, children is the right choice.
  5. Resetting scroll position: After a route change, scrollX and scrollY on the window should be reset to zero so the new page starts at the top.

The renderRoute Function

JavaScript
// router.js import MenuPage from './pages/MenuPage.js'; import DetailsPage from './pages/DetailsPage.js'; import CartPage from './pages/CartPage.js'; export function renderRoute(route) { let pageElement; switch (route) { case '/': pageElement = MenuPage.create(); break; case '/cart': pageElement = CartPage.create(); break; default: pageElement = MenuPage.create(); } const main = document.querySelector('main'); if (main.children[0]) { main.children[0].remove(); } main.appendChild(pageElement); window.scrollX = 0; window.scrollY = 0; }

The switch maps each known route to a page factory. The default case handles unknown routes by falling back to the menu - the same role a 404 page would serve in a server-rendered app.

Page Elements as Factory Functions

Each page is a module that exports a create function. The function builds and returns a DOM element. It does not know about the router or the container - it only knows how to build its own markup.

JavaScript
// pages/MenuPage.js const MenuPage = { create() { const section = document.createElement('section'); section.id = 'menu'; // ... populate with items from Store return section; } }; export default MenuPage;

renderRoute calls create(), gets back an element, and inserts it. The page itself stays decoupled from navigation.

Clearing the Container: children vs childNodes

Before inserting the new page, the old one has to go. There are two ways to read what is in the container.

main.children returns an HTMLCollection of child elements only. Text nodes, comments, and whitespace in the HTML are excluded.

main.childNodes returns a NodeList of all child nodes: elements, text nodes, comment nodes, and anything else.

For clearing a container that holds rendered page elements, children is the right tool:

JavaScript
if (main.children[0]) { main.children[0].remove(); }

Using childNodes[0] could accidentally grab a text node (a newline, for instance, left by whitespace in the HTML). That node removal would succeed without clearing the visible page.

Why Not innerHTML = ''

Setting innerHTML = '' is a common shortcut for clearing a container. It works, but it bypasses event listener cleanup. If the page element has child elements with registered handlers, those handlers are not removed - they simply become unreachable as the element is discarded. For short-lived small apps this is fine. For a long-running SPA with heavy views, it can become a source of memory growth over time.

The remove() approach is more deliberate: remove the specific element you know is there.

Scroll Reset

After a route change, the window scroll position carries over from the previous page. A user who scrolled to the bottom of the menu page should not see the cart page loaded mid-scroll.

JavaScript
window.scrollX = 0; window.scrollY = 0;

These assignments reset the scroll to the top-left corner after each route change. In most SPAs the only relevant axis is scrollY (vertical), but resetting both costs nothing.

Further Reading and Watching

Video: