slab/quill · error · Error

Syntax module requires highlight.js. Please include the libr

Error message

Syntax module requires highlight.js. Please include the library on the page before Quill.

What it means

The Syntax module tokenizes code blocks with highlight.js. Its DEFAULTS.hljs is captured as window.hljs at module-evaluation time (packages/quill/src/modules/syntax.ts:336-338), and the constructor throws if this.options.hljs is still null when the module is constructed. Unlike formula, you can inject the library via the module options instead of relying on the global.

Source

Thrown at packages/quill/src/modules/syntax.ts:218

  }
  return lib.highlight(language, text).value;
};

class Syntax extends Module<SyntaxOptions> {
  static DEFAULTS: SyntaxOptions & { hljs: any };

  static register() {
    Quill.register(CodeToken, true);
    Quill.register(SyntaxCodeBlock, true);
    Quill.register(SyntaxCodeBlockContainer, true);
  }

  languages: Record<string, true>;

  constructor(quill: Quill, options: Partial<SyntaxOptions>) {
    super(quill, options);
    if (this.options.hljs == null) {
      throw new Error(
        'Syntax module requires highlight.js. Please include the library on the page before Quill.',
      );
    }
    // @ts-expect-error Fix me later
    this.languages = this.options.languages.reduce(
      (memo: Record<string, unknown>, { key }) => {
        memo[key] = true;
        return memo;
      },
      {},
    );
    this.highlightBlot = this.highlightBlot.bind(this);
    this.initListener();
    this.initTimer();
  }

  initListener() {
    this.quill.on(Quill.events.SCROLL_BLOT_MOUNT, (blot: Blot) => {

View on GitHub (pinned to 539cbffd0a)

Solutions

  1. Pass the highlight.js instance explicitly via module options so the global capture is bypassed: modules: { syntax: { hljs } }.
  2. Import highlight.js and expose it globally before Quill initializes: import hljs from 'highlight.js'; (window as any).hljs = hljs;.
  3. Include the highlight.js <script> synchronously before the Quill init script.
  4. If code highlighting is optional, gate the syntax module behind a feature flag and only enable it when hljs is available.

Example fix

// before - relies on window.hljs captured at module-eval time
new Quill(el, { modules: { syntax: true } }); // throws if hljs missing

// after - inject hljs explicitly via options (preferred)
import hljs from 'highlight.js';
new Quill(el, {
  modules: { syntax: { hljs } },
});

// or expose globally before construction
import hljs from 'highlight.js';
(window as any).hljs = hljs;
new Quill(el, { modules: { syntax: true } });
Defensive patterns

Strategy: validation

Validate before calling

// Ensure highlight.js is available before enabling the syntax module
function resolveHljs(explicitHljs) {
  const hljs = explicitHljs ?? (typeof window !== 'undefined' ? window.hljs : undefined);
  if (hljs == null) {
    throw new Error(
      'Syntax module requires highlight.js. Pass it via modules.syntax.hljs or load window.hljs before Quill.',
    );
  }
  return hljs;
}

// usage
const hljs = resolveHljs(myHljsInstance);
new Quill(el, { modules: { syntax: { hljs } } });

Type guard

function hasHljs(explicitHljs) {
  const hljs = explicitHljs ?? (typeof window !== 'undefined' ? window.hljs : undefined);
  return hljs != null && typeof hljs.highlight === 'function';
}

// usage
if (hasHljs()) {
  new Quill(el, { modules: { syntax: true } });
} else {
  // skip syntax highlighting, or import highlight.js then retry
  new Quill(el, {});
}

Try / catch

try {
  new Quill(el, { modules: { syntax: { hljs } } });
} catch (err) {
  if (String(err?.message).includes('highlight.js')) {
    // hljs missing - initialize Quill without the syntax module
    console.warn('Syntax module disabled: highlight.js not available.');
    new Quill(el, { modules: { syntax: false } });
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: new Quill(el, { modules: { syntax: true } }) when window.hljs was undefined at the time Syntax.DEFAULTS was evaluated; highlight.js loaded asynchronously after Quill initializes; bundler/SSR environment with no window.hljs and no explicit hljs option passed; hljs option omitted from module config.

Common situations: Forgot the highlight.js script tag; highlight.js imported as a module but never assigned to window; tree-shaking dropping the side effect; Quill initialized before highlight.js finished loading; SSR rendering where window is absent.

Related errors


AI-assisted analysis of slab/quill@539cbffd0a (2026-08-12). Data as JSON: /api/errors/4ea6514045e9af31. Report an issue: GitHub.