slab/quill · critical · Error
Invalid theme ${options.theme}. Did you register it?
Error message
Invalid theme ${options.theme}. Did you register it? What it means
In expandConfig, when options.theme differs from Quill.DEFAULTS.theme (the built-in 'snow'), Quill resolves the theme class via Quill.import(`themes/${options.theme}`). Quill.import returns undefined for an unregistered path and logs a debug error, and expandConfig then throws because the theme class is required to construct the editor. Quill v2 only registers the default theme; every other theme (including the built-in 'bubble') must be explicitly imported/registered.
Source
Thrown at packages/quill/src/core/quill.ts:808
);
}
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 &&
userModuleOptions.toolbar &&
userModuleOptions.toolbar.constructor !== Object
) {
userModuleOptions = {
...userModuleOptions,
toolbar: { container: userModuleOptions.toolbar },
};
}
View on GitHub (pinned to 539cbffd0a)
Solutions
- Import and register the built-in bubble theme before construction: import BubbleTheme from 'quill/themes/bubble'; Quill.register('themes/bubble', BubbleTheme);.
- For a custom theme class, register it: Quill.register('themes/my-theme', MyTheme) (or rely on its side-effect import).
- Double-check the theme string spelling matches a registered path exactly (themes/<name>).
- If you do not need a custom theme, omit the theme option to fall back to the always-registered default 'snow' theme.
Example fix
// before - bubble theme never registered
new Quill(el, { theme: 'bubble' }); // throws: Invalid theme bubble
// after - register the theme first
import { Quill } from 'quill';
import BubbleTheme from 'quill/themes/bubble';
Quill.register('themes/bubble', BubbleTheme);
new Quill(el, { theme: 'bubble' }); Defensive patterns
Strategy: validation
Validate before calling
// Confirm the theme is registered before constructing Quill
import { Quill } from 'quill';
function assertThemeRegistered(themeName) {
const isDefault = !themeName || themeName === Quill.DEFAULTS.theme;
if (isDefault) return; // 'snow' is always registered
const theme = Quill.import(`themes/${themeName}`);
if (!theme) {
throw new Error(
`Theme "${themeName}" is not registered. Import it and call Quill.register('themes/${themeName}', ThemeClass).`,
);
}
}
// usage
assertThemeRegistered(options.theme);
new Quill(el, options); Type guard
function isThemeRegistered(themeName) {
if (!themeName || themeName === Quill.DEFAULTS.theme) return true;
return Quill.import(`themes/${themeName}`) != null;
}
// usage
if (isThemeRegistered('bubble')) {
new Quill(el, { theme: 'bubble' });
} Try / catch
try {
new Quill(el, { theme });
} catch (err) {
if (String(err?.message).startsWith('Invalid theme')) {
// theme not registered - fall back to default or register then retry once
Quill.register(`themes/${theme}`, FallbackThemeClass);
new Quill(el, { theme });
} else {
throw err;
}
} Prevention
- Register every non-default theme via Quill.register('themes/<name>', ThemeClass) at app bootstrap.
- Keep a single registration module (e.g., quill-setup.ts) imported once at app entry to avoid tree-shaking dropping side effects.
- Validate the theme name resolves with Quill.import before constructing Quill.
- Omit the theme option when you only need the default 'snow' theme.
When it happens
Trigger: new Quill(el, { theme: 'bubble' }) without importing/registering the bubble theme; referencing a custom theme name that was never passed to Quill.register; a typo in the theme string; tree-shaking removing the theme module's registration side effect.
Common situations: Quill v1->v2 migration where bubble was bundled by default; using ESM tree-shaking builds that drop the theme import; loading only packages/quill/src/core and expecting all themes present; custom theme class authored but not registered.
Related errors
AI-assisted analysis of slab/quill@539cbffd0a (2026-08-12).
Data as JSON: /api/errors/32ed642bf2ceacbd.
Report an issue: GitHub.