{"record":{"id":"1d0de15734102739","repo":"Shopify/draggable","slug":"draggable-containers-are-expected-to-be-of-type-n","errorCode":null,"errorMessage":"Draggable containers are expected to be of type `NodeList`, `HTMLElement[]` or `HTMLElement`","messagePattern":"Draggable containers are expected to be of type `NodeList`, `HTMLElement\\[\\]` or `HTMLElement`","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/Draggable/Draggable.js","lineNumber":115,"sourceCode":"\n  /**\n   * Draggable constructor.\n   * @constructs Draggable\n   * @param {HTMLElement[]|NodeList|HTMLElement} containers - Draggable containers\n   * @param {Object} options - Options for draggable\n   */\n  constructor(containers = [document.body], options = {}) {\n    /**\n     * Draggable containers\n     * @property containers\n     * @type {HTMLElement[]}\n     */\n    if (containers instanceof NodeList || containers instanceof Array) {\n      this.containers = [...containers];\n    } else if (containers instanceof HTMLElement) {\n      this.containers = [containers];\n    } else {\n      throw new Error(\n        'Draggable containers are expected to be of type `NodeList`, `HTMLElement[]` or `HTMLElement`',\n      );\n    }\n\n    this.options = {\n      ...defaultOptions,\n      ...options,\n      classes: {\n        ...defaultClasses,\n        ...(options.classes || {}),\n      },\n      announcements: {\n        ...defaultAnnouncements,\n        ...(options.announcements || {}),\n      },\n      exclude: {\n        plugins: (options.exclude && options.exclude.plugins) || [],\n        sensors: (options.exclude && options.exclude.sensors) || [],","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/Shopify/draggable/blob/8a1eed57f3ab2dff9371e8ce60fb39ac85871e8d/src/Draggable/Draggable.js#L97-L133","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Pass the result of `document.querySelectorAll('.my-class')` (a NodeList), `document.getElementById('id')`, or an array of HTMLElements directly as the first argument","If you only have a CSS selector string, resolve it first: `const containers = document.querySelectorAll(selector); if (containers.length) new Draggable(containers, options)`","For framework refs, unwrap before constructing: `new Draggable(ref.current, options)`","Ensure the constructor runs after the DOM exists (script at end of body, DOMContentLoaded listener, or useEffect/useMounted) so queries do not return null","Log the value with `console.log(containers instanceof NodeList, containers instanceof HTMLElement)` to confirm the runtime type matches the accepted types"],"exampleFix":"// before\nconst draggable = new Draggable('.draggable-container', {});\n\n// after\nconst containers = document.querySelectorAll('.draggable-container');\nconst draggable = new Draggable(containers, {});","handlingStrategy":"validation","validationCode":"function canConstructDraggable(containers) {\n  return (\n    containers instanceof NodeList ||\n    containers instanceof Array ||\n    containers instanceof HTMLElement\n  );\n}\n// usage: guard before constructing\nif (!canConstructDraggable(containers)) {\n  throw new TypeError('containers must be a NodeList, HTMLElement[] or HTMLElement');\n}\nconst draggable = new Draggable(containers, options);","typeGuard":"function isDraggableContainers(v) {\n  return v instanceof NodeList || v instanceof HTMLElement ||\n    (Array.isArray(v) && v.length > 0 && v.every((el) => el instanceof HTMLElement));\n}","tryCatchPattern":"let draggable;\ntry {\n  draggable = new Draggable(containers, options);\n} catch (e) {\n  if (e.message.includes('Draggable containers are expected')) {\n    console.error('Bad containers argument:', containers);\n    draggable = null; // fall back / disable dragging\n  } else {\n    throw e;\n  }\n}","preventionTips":["Always pass DOM elements/NodeLists, never CSS selector strings — resolve selectors yourself first","Check that querySelector/querySelectorAll did not return null/empty before constructing","Unwrap framework refs (ref.current) before passing them","Run initialization after the DOM is ready (defer script, DOMContentLoaded, useEffect)"],"tags":["javascript","dom","constructor","type-error","argument-validation"],"backgroundTag":"invalid-constructor-argument","analyzedSha":"8a1eed57f3ab2dff9371e8ce60fb39ac85871e8d","analyzedAt":"2026-09-02T20:51:07.383Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}