usablica/intro.js · error

Element with selector ${selector} not found

Error message

Element with selector ${selector} not found

What it means

getElement() resolves a CSS selector via queryElement() and throws when nothing matches in the document (or the optional container). Unlike queryElement(), which returns null, getElement() is the strict variant asserting the element must exist, used to initialize tours/hints against required DOM nodes.

Source

Thrown at src/util/queryElement.ts:29

): NodeListOf<HTMLElement> => {
  return (container ?? document).querySelectorAll(selector);
};

export const queryElementsByClassName = (
  className: string,
  container?: HTMLElement | null
): NodeListOf<HTMLElement> => {
  return queryElements(`.${className}`, container);
};

export const getElement = (
  selector: string,
  container?: HTMLElement | null
) => {
  const element = queryElement(selector, container);

  if (!element) {
    throw new Error(`Element with selector ${selector} not found`);
  }

  return element;
};

View on GitHub (pinned to e5517e6a24)

Solutions

  1. Call the tour/hint setup after the DOM element exists (on mount / DOMContentLoaded / after render).
  2. Verify the selector matches in DevTools (document.querySelector(selector) !== null) — check for missing '.', '#', typos.
  3. Pass the correct container argument if the element lives inside a specific container.
  4. If the element is optional, use queryElement() (returns null) instead of getElement().

Example fix

// before
introJs.tour('#save-button'); // may run before render
// after
document.addEventListener('DOMContentLoaded', () => {
  if (document.querySelector('#save-button')) introJs.tour('#save-button');
});
Defensive patterns

Strategy: validation

Validate before calling

const el = document.querySelector('#save-button');
if (!el) throw new Error('#save-button missing — aborting tour setup');
introJs.tour('#save-button');

Type guard

function elementExists(selector: string, root: ParentNode = document): boolean {
  return root.querySelector(selector) !== null;
}

Try / catch

try {
  introJs.tour('#save-button');
} catch (e) {
  if (String(e.message).includes('not found')) {
    console.warn('Tour target missing, skipping intro:', e.message);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling introJs.tour('#step-1') or any API that runs getElement() with a selector that matches no element, a misspelled selector, an element inside a container passed as null, or an element not yet rendered when the call executes.

Common situations: Calling intro before the DOM has rendered (scripts in <head>, SPA route mount race, dynamic content not yet injected); typo in class/id (missing dot or hash); element only exists conditionally; SSR where document has no such element; scoping to a container that doesn't contain the node.


AI-assisted analysis of usablica/intro.js@e5517e6a24 (2026-08-31). Data as JSON: /api/errors/79f33b1634ca8a31. Report an issue: GitHub.