slab/quill · critical · Error
Invalid Quill container
Error message
Invalid Quill container
What it means
expandConfig (packages/quill/src/core/quill.ts:793) calls resolveSelector on the container argument; resolveSelector runs document.querySelector for a string and returns the element directly otherwise. If the result is falsy it throws 'Invalid Quill container'. Quill needs a real, mounted DOM node to attach to before any editor wiring can run.
Source
Thrown at packages/quill/src/core/quill.ts:799
[key]: value === true ? {} : value,
}),
{} as Record<string, unknown>,
);
}
function omitUndefinedValuesFromOptions(obj: QuillOptions) {
return Object.fromEntries(
Object.entries(obj).filter((entry) => entry[1] !== undefined),
);
}
function expandConfig(
containerOrSelector: HTMLElement | string,
options: QuillOptions,
): ExpandedQuillOptions {
const container = resolveSelector(containerOrSelector);
if (!container) {
throw new Error('Invalid Quill container');
}
const shouldUseDefaultTheme =
!options.theme || options.theme === Quill.DEFAULTS.theme;
const theme = shouldUseDefaultTheme
? Theme
: Quill.import(`themes/${options.theme}`);
if (!theme) {
throw new Error(`Invalid theme ${options.theme}. Did you register it?`);
}
const { modules: quillModuleDefaults, ...quillDefaults } = Quill.DEFAULTS;
const { modules: themeModuleDefaults, ...themeDefaults } = theme.DEFAULTS;
let userModuleOptions = expandModuleConfig(options.modules);
// Special case toolbar shorthand
if (
userModuleOptions != null &&View on GitHub (pinned to 539cbffd0a)
Solutions
- Defer initialization until the element exists: run new Quill inside DOMContentLoaded, or in the framework's onMounted/afterViewInit/componentDidMount lifecycle hook.
- Pass the element reference directly instead of a selector string: new Quill(document.getElementById('editor')) to remove querySelector ambiguity.
- Verify the selector resolves before constructing: if (!document.querySelector(sel)) return;.
- In an SPA, ensure the container is rendered (v-if resolved) before the Quill initialization effect runs.
Example fix
// before - runs before #editor is in the DOM
new Quill('#editor'); // throws: Invalid Quill container
// after - resolve and guard, then pass the element
const el = document.querySelector('#editor');
if (!el) throw new Error('#editor not found');
new Quill(el, { theme: 'snow' });
// or, in Vue/React, inside onMounted / useEffect where the ref is set Defensive patterns
Strategy: validation
Validate before calling
// Resolve the container yourself before constructing Quill
function resolveQuillContainer(target) {
const el =
typeof target === 'string'
? document.querySelector(target)
: target;
if (!el || !(el instanceof HTMLElement)) {
throw new Error(
`Invalid Quill container: ${typeof target === 'string' ? target : 'provided element'} is not a mounted HTMLElement`,
);
}
return el;
}
// usage
const el = resolveQuillContainer('#editor');
new Quill(el, { theme: 'snow' }); Type guard
function isMountedHTMLElement(value) {
return value instanceof HTMLElement && document.body.contains(value);
}
// usage
const el = document.querySelector('#editor');
if (isMountedHTMLElement(el)) {
new Quill(el);
} Prevention
- Initialize Quill inside the framework's post-mount lifecycle (onMounted/useEffect/afterViewInit), not in created/setup.
- Pass the resolved HTMLElement directly rather than a selector string to eliminate querySelector ambiguity.
- For script-tag usage, place the script at the end of <body> or defer it until DOMContentLoaded.
- In SPAs with conditional rendering, confirm the container ref is populated before the init effect runs.
When it happens
Trigger: Passing a CSS selector string that matches no element; calling new Quill('#editor') before the element is in the DOM (script in head without defer, or running before DOMContentLoaded); passing a detached/removed HTMLElement; running where document is absent (SSR) so querySelector returns null.
Common situations: Script tag in <head> executing before the body is parsed; SPA frameworks instantiating Quill in created() instead of mounted()/onMounted(); selector typo or renamed element id; hydration races where the container is conditionally rendered.
Related errors
- Cannot initialize Quill without "${scrollBlotName}" blot
- Invalid theme ${options.theme}. Did you register it?
AI-assisted analysis of slab/quill@539cbffd0a (2026-08-12).
Data as JSON: /api/errors/66a987de24408a08.
Report an issue: GitHub.