Web APIs Cheatsheet

History and URL

Use this Web APIs reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

window.location

// Read-only snapshot of current URL
location.href;       // 'https://example.com:8080/path?q=1#hash'
location.origin;     // 'https://example.com:8080'
location.protocol;   // 'https:'
location.host;       // 'example.com:8080'
location.hostname;   // 'example.com'
location.port;       // '8080'
location.pathname;   // '/path'
location.search;     // '?q=1'
location.hash;       // '#hash'

// Navigate (adds to history)
location.href = 'https://example.com/new';
location.assign('https://example.com/new');

// Navigate without adding to history
location.replace('https://example.com/new');

// Reload
location.reload();

// Write individual parts (triggers navigation)
location.pathname = '/other';
location.search   = '?page=2';
location.hash     = '#section';

History API

Basic Navigation

history.length;          // number of entries in session history
history.scrollRestoration; // 'auto' | 'manual'
history.state;           // current state object (or null)

history.back();          // equivalent to browser Back
history.forward();       // equivalent to browser Forward
history.go(0);           // reload
history.go(-2);          // 2 steps back
history.go(1);           // 1 step forward

pushState and replaceState

// pushState(state, unused, url)
// url must be same origin; can be relative; does NOT trigger navigation
history.pushState({ page: 2 }, '', '/products?page=2');
history.pushState(null, '', '/about');

// replaceState — updates current entry without adding a new one
history.replaceState({ page: 2 }, '', '/products?page=2');
pushStatereplaceState
Adds to history stackYesNo
Fires popstateNoNo
Triggers page loadNoNo
URL must be same-originYesYes

popstate Event

// Fires on back/forward navigation (NOT on pushState/replaceState)
window.addEventListener('popstate', e => {
  console.log('State:', e.state);      // the state object passed to push/replace
  console.log('Path:', location.pathname);
  renderPage(location.pathname, e.state);
});

popstate fires when the user navigates the history stack (back/forward button or history.go()). It does not fire for pushState/replaceState.

hashchange Event

window.addEventListener('hashchange', e => {
  e.oldURL; // full URL before hash change
  e.newURL; // full URL after hash change
  console.log(location.hash); // e.g. '#section-2'
});

URL API

const url = new URL('https://example.com:8080/path?q=hello&page=2#top');

url.href;         // full URL string
url.origin;       // 'https://example.com:8080'
url.protocol;     // 'https:'
url.host;         // 'example.com:8080'
url.hostname;     // 'example.com'
url.port;         // '8080'
url.pathname;     // '/path'
url.search;       // '?q=hello&page=2'
url.hash;         // '#top'
url.username;     // '' (http://user:pass@host)
url.password;     // ''

// Modify and serialize
url.pathname = '/new-path';
url.searchParams.set('page', 3);
url.toString();   // updated URL string

// Relative URL (resolve against base)
const rel = new URL('/about', 'https://example.com');
rel.href; // 'https://example.com/about'

// Static
URL.canParse('not a url');           // false
URL.parse('https://example.com');    // URL | null (no throw)

URLSearchParams

// From URL
const params = new URL(location.href).searchParams;

// From string
const params = new URLSearchParams('q=hello&page=2&tag=js&tag=ts');

// From object
const params = new URLSearchParams({ q: 'hello', page: '2' });

// From entries
const params = new URLSearchParams([['q', 'hello'], ['page', '2']]);

// Read
params.get('q');                  // 'hello' (first value) or null
params.getAll('tag');             // ['js', 'ts']
params.has('page');               // true
params.size;                      // number of entries

// Write
params.set('page', '3');          // replace all 'page' values
params.append('tag', 'css');      // add (keeps existing)
params.delete('q');               // remove all 'q'
params.delete('tag', 'js');       // remove specific value (modern)
params.sort();                    // sort by key (stable, Unicode order)

// Iterate
for (const [key, value] of params) { /* … */ }
params.forEach((value, key) => { /* … */ });
[...params.keys()];
[...params.values()];
[...params.entries()];

// Serialize
params.toString();                // 'page=3&tag=ts&tag=css' (URL-encoded)

// Attach to URL
url.search = params.toString();
// or
url.searchParams.set('key', 'val'); // URLSearchParams is live on URL object

SPA Router Pattern (History API)

// Link interception
document.addEventListener('click', e => {
  const a = e.target.closest('a[href]');
  if (!a) return;
  const url = new URL(a.href);
  if (url.origin !== location.origin) return; // let external links through
  e.preventDefault();
  history.pushState(null, '', url.pathname + url.search + url.hash);
  router(url.pathname);
});

// Handle back/forward
window.addEventListener('popstate', () => router(location.pathname));

// Initial load
router(location.pathname);

function router(path) {
  const route = routes.find(r => r.pattern.test(path));
  if (route) route.render(path);
}

URL Encoding Utilities

// Encode a full URL (keeps special URL chars)
encodeURI('https://example.com/path with spaces');
// 'https://example.com/path%20with%20spaces'

// Encode a URI component (encodes everything except unreserved chars)
encodeURIComponent('hello world & more');
// 'hello%20world%20%26%20more'

decodeURI('%20');
decodeURIComponent('%20');

// URLSearchParams handles encoding automatically
const p = new URLSearchParams({ q: 'hello world & more' });
p.toString(); // 'q=hello+world+%26+more' (+ for spaces in query strings)

Gotchas

  • pushState/replaceState URLs must be same-origin — passing a cross-origin URL throws a SecurityError.
  • The second argument to pushState/replaceState (title) is ignored by all browsers.
  • history.state is serialized with the structured clone algorithm — functions, DOM nodes, and class instances are not preserved.
  • popstate does NOT fire on page load — read history.state directly on initial render.
  • URLSearchParams uses + for spaces when serialized, but %20 within URL path components.