October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsClean PCRecommendedOne scan can reveal what keeps slowing WindowsLook for cleanup and repair opportunities.Run ScanOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
World desk5 min

Understanding State in a Vanilla JavaScript Web App

A practical guide to state in vanilla JavaScript: update data and render the UI, then choose storage or browser history based on the lifetime and role of the data.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

In a vanilla JavaScript app, state is the data that describes what the app is doing right now—for example, which panel is open or which item is selected. Keep that data in JavaScript, update it when users act, then render the interface from the updated data. Choose persistence separately: in-memory data resets on reload, while browser storage and the History API serve different lifetimes and purposes.

What state means in a JavaScript app

State is the app’s current data, not the HTML currently visible on screen. A small app might hold it in an ordinary object, array, or primitive. The DOM is the visible projection of that data; keeping the model distinct from the markup makes it easier to update or reconstruct a view.

A useful design loop is:

  1. Initialize the state your app needs.
  2. Listen for a user action.
  3. Update the relevant state value.
  4. Render the affected interface from the updated state.

This is a design pattern, not a browser requirement or a framework. It helps avoid relying on DOM nodes as the only place important app data exists.

Keep state and rendering in sync

For a small interface, a render function can derive visible content from a single state object. The event handler changes the data first and then renders, so the view reflects the current model.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
const state = { count: 0 };
const output = document.querySelector("#count");
const button = document.querySelector("#increment");

function render() {
  output.textContent = String(state.count);
}

button.addEventListener("click", () => {
  state.count += 1;
  render();
});

render();

For larger interfaces, render only the part affected by a change if that keeps the code clearer or avoids unnecessary work. The essential rule stays the same: update the source data deliberately, then make the visible UI agree with it.

Where should app state live?

Pick a location by asking how long the data must last, whether it needs to survive reloads, and how much data or activity is involved. Browser storage is a persistence decision, not a replacement for the app’s in-memory working state.

Choice Lifetime and scope Good fit Main trade-off
In-memory JavaScript data Current loaded page Transient UI and working state Lost on full reload unless reconstructed
sessionStorage Origin and browser tab; cleared when the tab closes Small per-tab state that should survive reloads Synchronous and not long-lived
localStorage Origin; ordinarily persists across browser close and reopen Small preferences or simple drafts Synchronous and shared by same-origin documents; private-mode data is temporary
IndexedDB Browser-managed client storage Larger datasets or cases needing asynchronous access More API complexity; requires a suitable schema and lifecycle
History API state A session-history entry SPA navigation and Back/Forward restoration Navigation-related serializable state, not a general persistence database

Use memory for temporary working state

An open menu, current selection, or unsaved interaction can stay in a JavaScript object while the page is loaded. If the page fully reloads, that in-memory data is gone unless your app can rebuild it from another source.

Use sessionStorage for small per-tab state

sessionStorage is partitioned by origin and browser tab. Its contents survive reloads in that tab but are destroyed when the tab closes, making it useful for modest state that should not become a lasting preference shared with future sessions.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use localStorage for modest data that should remain

localStorage is partitioned by origin and is available to documents from that same origin. In ordinary browsing it persists across browser restarts. In private browsing, MDN documents that it is treated like sessionStorage and deleted when the private browser or tab closes. These lifetime and scope details are described in MDN’s Web Storage API documentation, last modified February 22, 2025.

Web Storage values are strings, so small objects are commonly serialized as JSON. Treat stored data as potentially stale or malformed, and validate it before using it. JSON serialization is not suitable for every JavaScript value, and browser storage should not be treated as secure storage for secrets.

const key = "app-preferences";
let preferences = { theme: "light" };

try {
  const saved = localStorage.getItem(key);
  if (saved !== null) {
    const parsed = JSON.parse(saved);
    if (parsed && typeof parsed.theme === "string") {
      preferences = parsed;
    }
  }
} catch {
  // Keep the default when stored data is unavailable or invalid.
}

function savePreferences() {
  try {
    localStorage.setItem(key, JSON.stringify(preferences));
  } catch {
    // Handle unavailable storage or a failed write as appropriate for the app.
  }
}

Consider IndexedDB when synchronous storage no longer fits

MDN notes that both localStorage and sessionStorage operate synchronously. Large or frequent reads and writes can block JavaScript and harm responsiveness. IndexedDB is an asynchronous alternative to consider when performance or dataset size calls for it; there is no single size threshold that applies to every app. See MDN’s Web Storage API documentation.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Handle Back and Forward in a single-page app

If an app changes views without loading a new document, browser navigation becomes part of its state. Without history entries for in-app views, Back may leave the app instead of returning to its previous view. The History API lets an SPA add an entry with history.pushState(), update the current entry with history.replaceState(), and respond to traversal with the popstate event. MDN’s guide explains this pattern and how to restore a prior view: Working with the History API, last modified August 1, 2025.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
function showView(view) {
  // Update the interface from the view data.
}

function navigateTo(view, url) {
  history.pushState(view, "", url);
  showView(view);
}

history.replaceState({ page: "home" }, "", location.href);
showView(history.state);

window.addEventListener("popstate", (event) => {
  showView(event.state);
});

Initialize the current entry with replaceState() when the starting view must also be restorable. The state associated with a history entry must be serializable, and the URL passed to pushState() or replaceState() must be same-origin. The History API’s title parameter is ignored by browsers other than Safari, so do not rely on it to change the tab title; MDN documents this in its History interface reference, last modified June 23, 2025.

History state can identify a view or carry enough information to restore it, but it is tied to navigation rather than intended as a database for large persistent datasets. Keep ordinary anchor behavior where it serves users, and use an SPA-style history flow only when the app actually changes content without document navigation.

A practical choice checklist

  • Does the value only matter while the page is loaded? Keep it in memory.
  • Should it survive reloads in one tab but disappear when that tab closes? Consider sessionStorage.
  • Should a small preference remain for later visits in ordinary browsing? Consider localStorage, with private-mode behavior in mind.
  • Is the data larger or are storage operations frequent enough that synchronous work is a concern? Consider IndexedDB.
  • Should Back and Forward restore an in-app view? Represent navigation with History API entries and handle popstate.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
PC Slower Than It Used to Be?Free scan - under a minute
Outdated Drivers Are Slowing You DownFree scan - exact matches

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.