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
- 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
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
- 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)
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.