Skip to main content
Most problems with Lumen Editor fall into a small set of categories: the editor fails to appear, content is not persisted, images silently fail to upload, or pasted content looks different from the source. This page walks through each issue, explains why it happens, and shows you exactly what to check or change to resolve it.

Common Issues

If the editor container appears blank or the toolbar is missing, work through the following checks in order.1. Ensure the target element exists before initialisationLumen attaches to a DOM element you supply. If that element does not exist at the time you call new Editor(), initialisation silently fails.
// ✅ Wait for the DOM to be ready
document.addEventListener('DOMContentLoaded', () => {
  const editor = new Editor('#my-editor', options);
});
2. Import the theme stylesheetWithout theme.css, the editor’s toolbar and content area have no layout styles and may collapse to zero height.
import 'lumen-editor/theme.css';
3. Give the container a heightThe editor fills the height of its container. If the container has no explicit height — and no content to stretch it — the editor will not be visible.
#my-editor {
  height: 400px; /* or min-height */
}
If the editor renders but looks unstyled — toolbar icons are missing, fonts are wrong, or the content area has no border — the most common cause is a missing CSS import.Make sure you import the Lumen theme before your own stylesheets so you can override individual rules where needed:
import 'lumen-editor/theme.css';
import './your-styles.css'; // overrides go here
If you are using a bundler that processes CSS (Vite, webpack, Parcel), confirm the import resolves correctly by checking your bundler’s output or the Network panel in DevTools.
autoSave key collisionThe autoSave feature persists content to localStorage using a key you provide. If two editor instances share the same key, they will overwrite each other’s data.
const editor = new Editor('#editor', {
  autoSave: { key: 'post-draft-42' }, // use a unique key per editor instance
});
Reading the latest content on changeIf you are manually saving content, call getHTML() inside the change event handler — not outside it. Calling it at a fixed point in time will return a stale snapshot.
editor.on('change', () => {
  const html = editor.getHTML();
  saveToServer(html);
});
uploadImage must return a URL stringIf your uploadImage handler throws an error or returns undefined, Lumen silently skips the image insertion. Make sure the function always resolves to a URL string.
const editor = new Editor('#editor', {
  uploadImage: async (file) => {
    const response = await fetch('/api/upload', {
      method: 'POST',
      body: createFormData(file),
    });
    const { url } = await response.json();
    return url; // must be a string
  },
});
Listen to the error event for diagnosticsUpload failures surface through the error event. Attach a listener during development to catch issues early:
editor.on('error', (e) => {
  console.warn(e.code, e.message);
});
Image validation rulesLumen validates images before calling uploadImage. An image is rejected if it fails any of the following checks:
  • MIME type is not an accepted image type
  • Magic bytes do not match the declared MIME type
  • File size exceeds the limit (default 5 MB)
If an image fails validation, uploadImage is never called and no error is thrown to your handler. The rejection is reported exclusively through the error event.
Sanitization is intentionalWhen you paste HTML into Lumen Editor, the content passes through a built-in, DOM-based sanitizer that strips any tags and attributes not on the allowlist. This is a security feature, not a bug — it prevents XSS payloads from entering the editor via the clipboard.Plain text pasted from any source is always safe and is never modified.Allowing additional tags and attributesIf your workflow requires preserving specific tags or attributes that Lumen strips by default, configure the sanitize option:
const editor = new Editor('#editor', {
  sanitize: {
    allowTags: ['mark', 'abbr'],
    allowAttributes: { abbr: ['title'] },
  },
});
Extend the allowlist only for tags and attributes you fully trust. Adding permissive rules — such as allowing style or event handler attributes — can reintroduce XSS risk.
Types are included in the packageLumen Editor ships its own TypeScript type definitions — you do not need to install a separate @types/lumen-editor package. The named export works directly:
import { Editor } from 'lumen-editor';
Exported typesThe following types are available for import alongside Editor:
import type {
  EditorOptions,
  EditorModule,
  EditorPlugin,
  EditorEvent,
} from 'lumen-editor';
If your editor reports that the module cannot be found, confirm that moduleResolution in your tsconfig.json is set to "bundler", "node16", or "nodenext" — older "node" resolution may not pick up the exports field in package.json.
Lumen Editor is CSP-compatible by designLumen does not use eval, new Function, inline <script> tags, or dynamic script injection. This means it works with strict Content Security Policies without any special exceptions.If you use strict-dynamic in your CSP header, you do not need to add a nonce or hash for Lumen Editor itself.A policy such as the following is fully compatible:
Content-Security-Policy:
  default-src 'self';
  script-src 'self' 'strict-dynamic';
  style-src 'self';
If you are seeing CSP violations in the console while using Lumen, the violation is most likely originating from another library, a browser extension, or an inline script elsewhere on the page — not from Lumen Editor itself.

Debugging Tips

When an issue is not immediately obvious, use the error event as your first diagnostic tool. Lumen surfaces internal errors — upload failures, sanitizer rejections, plugin faults — with a structured code and message:
editor.on('error', (e) => {
  console.warn('[lumen-editor]', e.code, e.message);
});
Common e.code values to watch for:
CodeMeaning
UPLOAD_FAILEDuploadImage threw or returned a non-string value
INVALID_MIMEImage file failed MIME type validation
MAGIC_BYTE_MISMATCHFile bytes do not match the declared MIME type
SIZE_EXCEEDEDImage exceeds the configured size limit
Open your browser’s DevTools → Elements panel and inspect the editor’s root DOM node. Lumen renders a standard contenteditable div — you can inspect its inner HTML directly, verify that sanitization is working as expected, and confirm that your container has non-zero dimensions using the Computed styles tab.