CKEditor 5 HTML Embed is a feature plugin that enables users to insert arbitrary HTML snippets directly into the editor as interactive widgets. It provides a secure way to embed custom HTML content while maintaining the editor's WYSIWYG experience through configurable sanitization and preview capabilities.
npm install @ckeditor/ckeditor5-html-embedimport { HtmlEmbed, HtmlEmbedEditing, HtmlEmbedUI, HtmlEmbedCommand } from '@ckeditor/ckeditor5-html-embed';
import type { HtmlEmbedConfig, HtmlEmbedSanitizeOutput, _RawHtmlEmbedApi } from '@ckeditor/ckeditor5-html-embed';
import { Command, Plugin, type Editor } from 'ckeditor5/src/core.js';
import { Widget } from 'ckeditor5/src/widget.js';For CommonJS:
const { HtmlEmbed, HtmlEmbedEditing, HtmlEmbedUI, HtmlEmbedCommand } = require('@ckeditor/ckeditor5-html-embed');import { ClassicEditor } from '@ckeditor/ckeditor5-editor-classic';
import { HtmlEmbed } from '@ckeditor/ckeditor5-html-embed';
ClassicEditor
.create(document.querySelector('#editor'), {
plugins: [HtmlEmbed],
toolbar: ['htmlEmbed'],
htmlEmbed: {
showPreviews: true,
sanitizeHtml: (inputHtml) => ({
html: inputHtml, // Implement proper sanitization
hasChanged: false
})
}
})
.then(editor => {
// Editor ready with HTML embed feature
const htmlEmbedCommand = editor.commands.get('htmlEmbed');
// Insert HTML embed programmatically
htmlEmbedCommand.execute('<div>Custom HTML content</div>');
});The HTML Embed feature is built around several key components:
// Base classes from CKEditor 5 core
class Plugin {
// Base plugin class
}
class Command {
// Base command class
}
class Widget {
// Widget functionality
}The primary plugin class that orchestrates the HTML embed feature.
class HtmlEmbed extends Plugin {
/**
* Required plugins for HTML embed functionality
*/
static readonly requires: readonly [typeof HtmlEmbedEditing, typeof HtmlEmbedUI, typeof Widget];
/**
* Plugin name identifier
*/
static readonly pluginName: 'HtmlEmbed';
/**
* Indicates this is an official CKEditor plugin
*/
static readonly isOfficialPlugin: true;
}Handles the editor model, schema, data conversion, and command registration.
class HtmlEmbedEditing extends Plugin {
/**
* Plugin name identifier
*/
static readonly pluginName: 'HtmlEmbedEditing';
/**
* Indicates this is an official CKEditor plugin
*/
static readonly isOfficialPlugin: true;
/**
* Creates a new instance of HtmlEmbedEditing plugin
* @param editor - The editor instance
*/
constructor(editor: Editor);
/**
* Initializes the editing functionality - sets up model schema,
* data conversion, and registers the htmlEmbed command
*/
init(): void;
}Provides user interface components including toolbar buttons and menu items.
class HtmlEmbedUI extends Plugin {
/**
* Plugin name identifier
*/
static readonly pluginName: 'HtmlEmbedUI';
/**
* Indicates this is an official CKEditor plugin
*/
static readonly isOfficialPlugin: true;
/**
* Creates a new instance of HtmlEmbedUI plugin
* @param editor - The editor instance
*/
constructor(editor: Editor);
/**
* Initializes UI components - registers toolbar and menu bar buttons
*/
init(): void;
}Command implementation for inserting and updating HTML embed elements.
class HtmlEmbedCommand extends Command {
/**
* Flag indicating whether the command can be executed
*/
readonly isEnabled: boolean;
/**
* Current value of selected HTML embed element, or null if none selected
*/
readonly value: string | null;
/**
* Creates a new instance of HtmlEmbedCommand
* @param editor - The editor instance
*/
constructor(editor: Editor);
/**
* Updates command state and value based on current selection
*/
refresh(): void;
/**
* Executes the command to insert new HTML embed or update existing one
* @param value - HTML content to insert or update with (optional)
*/
execute(value?: string): void;
}Usage Example:
// Get the command instance
const htmlEmbedCommand = editor.commands.get('htmlEmbed');
// Check if command is enabled
if (htmlEmbedCommand.isEnabled) {
// Insert new HTML embed
htmlEmbedCommand.execute('<iframe src="https://example.com"></iframe>');
}
// Check current HTML embed value (if selection is on HTML embed)
const currentValue = htmlEmbedCommand.value;
if (currentValue) {
// Update existing HTML embed
htmlEmbedCommand.execute('<div>Updated content</div>');
}Configuration interface for customizing HTML embed behavior.
interface HtmlEmbedConfig {
/**
* Whether to render previews of embedded HTML (default: false)
*/
showPreviews?: boolean;
/**
* Function to sanitize HTML for preview rendering
*/
sanitizeHtml?: (html: string) => HtmlEmbedSanitizeOutput;
}Configuration Example:
ClassicEditor.create(editorElement, {
htmlEmbed: {
showPreviews: true,
sanitizeHtml: (inputHtml) => {
// Implement sanitization logic here
const sanitizedHtml = sanitizeHtmlContent(inputHtml);
return {
html: sanitizedHtml,
hasChanged: sanitizedHtml !== inputHtml
};
}
}
});Structure returned by the sanitization function.
interface HtmlEmbedSanitizeOutput {
/**
* Sanitized HTML that will be rendered in the preview
*/
html: string;
/**
* Flag indicating if sanitization modified the input
*/
hasChanged: boolean;
}Internal API exposed on HTML embed widgets for programmatic control.
interface _RawHtmlEmbedApi {
/**
* Switch widget to editable mode
*/
makeEditable(): void;
/**
* Save changes to widget content
*/
save(newValue: string): void;
/**
* Cancel editing and revert to non-editable mode
*/
cancel(): void;
}Note: This is an internal API (prefixed with underscore) and should not be used in regular implementations.
The HTML Embed feature includes important security considerations:
showPreviews is enabled, implement proper sanitizeHtml function to prevent XSS vulnerabilitiesSecure Configuration Example:
import sanitizeHtml from 'sanitize-html';
ClassicEditor.create(editorElement, {
htmlEmbed: {
showPreviews: true,
sanitizeHtml: (inputHtml) => {
const cleanHtml = sanitizeHtml(inputHtml, {
allowedTags: ['div', 'span', 'p', 'br'],
allowedAttributes: {
'div': ['class'],
'span': ['class']
}
});
return {
html: cleanHtml,
hasChanged: cleanHtml !== inputHtml
};
}
}
});The HTML Embed feature uses the following data structures:
rawHtml - Block-level element in the CKEditor modelvalue - Stores the HTML content as a stringdiv.raw-html-embed elements and rawHtml model elements$blockObject and allows the value attributeRequired CKEditor 5 packages:
@ckeditor/ckeditor5-core - Core plugin and command classes@ckeditor/ckeditor5-ui - UI components and button implementations@ckeditor/ckeditor5-widget - Widget functionality for proper selection behavior@ckeditor/ckeditor5-utils - Utility functions@ckeditor/ckeditor5-icons - Icon resources for UI components