Shopify/draggable · error

Draggable containers are expected to be of type `NodeList`,

Error message

Draggable containers are expected to be of type `NodeList`, `HTMLElement[]` or `HTMLElement`

What it means

This error is thrown by the Draggable constructor when the `containers` argument is not one of the accepted types: a NodeList, an array of HTMLElements, or a single HTMLElement. Draggable needs one or more container elements to scope which DOM regions are draggable, and it normalizes the input into an internal `containers` array. If the value passed is anything else (string selector, null, jQuery object, etc.), the constructor cannot proceed and throws immediately.

Source

Thrown at src/Draggable/Draggable.js:115

  /**
   * Draggable constructor.
   * @constructs Draggable
   * @param {HTMLElement[]|NodeList|HTMLElement} containers - Draggable containers
   * @param {Object} options - Options for draggable
   */
  constructor(containers = [document.body], options = {}) {
    /**
     * Draggable containers
     * @property containers
     * @type {HTMLElement[]}
     */
    if (containers instanceof NodeList || containers instanceof Array) {
      this.containers = [...containers];
    } else if (containers instanceof HTMLElement) {
      this.containers = [containers];
    } else {
      throw new Error(
        'Draggable containers are expected to be of type `NodeList`, `HTMLElement[]` or `HTMLElement`',
      );
    }

    this.options = {
      ...defaultOptions,
      ...options,
      classes: {
        ...defaultClasses,
        ...(options.classes || {}),
      },
      announcements: {
        ...defaultAnnouncements,
        ...(options.announcements || {}),
      },
      exclude: {
        plugins: (options.exclude && options.exclude.plugins) || [],
        sensors: (options.exclude && options.exclude.sensors) || [],

View on GitHub (pinned to 8a1eed57f3)

Solutions

  1. Pass the result of `document.querySelectorAll('.my-class')` (a NodeList), `document.getElementById('id')`, or an array of HTMLElements directly as the first argument
  2. If you only have a CSS selector string, resolve it first: `const containers = document.querySelectorAll(selector); if (containers.length) new Draggable(containers, options)`
  3. For framework refs, unwrap before constructing: `new Draggable(ref.current, options)`
  4. Ensure the constructor runs after the DOM exists (script at end of body, DOMContentLoaded listener, or useEffect/useMounted) so queries do not return null
  5. Log the value with `console.log(containers instanceof NodeList, containers instanceof HTMLElement)` to confirm the runtime type matches the accepted types

Example fix

// before
const draggable = new Draggable('.draggable-container', {});

// after
const containers = document.querySelectorAll('.draggable-container');
const draggable = new Draggable(containers, {});
Defensive patterns

Strategy: validation

Validate before calling

function canConstructDraggable(containers) {
  return (
    containers instanceof NodeList ||
    containers instanceof Array ||
    containers instanceof HTMLElement
  );
}
// usage: guard before constructing
if (!canConstructDraggable(containers)) {
  throw new TypeError('containers must be a NodeList, HTMLElement[] or HTMLElement');
}
const draggable = new Draggable(containers, options);

Type guard

function isDraggableContainers(v) {
  return v instanceof NodeList || v instanceof HTMLElement ||
    (Array.isArray(v) && v.length > 0 && v.every((el) => el instanceof HTMLElement));
}

Try / catch

let draggable;
try {
  draggable = new Draggable(containers, options);
} catch (e) {
  if (e.message.includes('Draggable containers are expected')) {
    console.error('Bad containers argument:', containers);
    draggable = null; // fall back / disable dragging
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: Calling `new Draggable('css-selector', options)` with a string selector instead of a NodeList/Element; passing null or undefined because the DOM query (`document.querySelectorAll(...)` or `document.getElementById(...)`) returned nothing or was forgotten; passing a jQuery object or a framework ref object (React ref, Vue ref) instead of the underlying DOM element.

Common situations: Migrating from selector-string-based drag libraries and passing a CSS selector string; running the constructor before the DOM is ready (script in <head> without defer) so querySelector returns null; wrapping elements in a framework and forwarding a ref object rather than ref.current; typos in element IDs/classes.

Related errors


AI-assisted analysis of Shopify/draggable@8a1eed57f3 (2026-09-02). Data as JSON: /api/errors/1d0de15734102739. Report an issue: GitHub.