Lightweight web-based rich text editor (WYSIWYG editor) built with JavaScript and CSS for modern browsers
—
Comprehensive configuration options for customizing editor behavior, appearance, and functionality.
All configuration is done through the customConfig property before calling create(). The configuration object provides extensive customization options for menus, styling, event handling, and functionality.
const editor = new wangEditor('#toolbar');
// Configure before creating
editor.customConfig.option = value;
editor.customConfig.onchange = function(html) { /* ... */ };
// Then create the editor
editor.create();Control which menu items appear in the toolbar.
interface MenuConfig {
/** Array of menu item names to display in toolbar */
menus?: string[];
}
// Default menu items
const defaultMenus = [
'head', // Heading styles
'bold', // Bold text
'fontSize', // Font size
'fontName', // Font family
'italic', // Italic text
'underline', // Underline text
'strikeThrough', // Strikethrough text
'foreColor', // Text color
'backColor', // Background color
'link', // Insert/edit links
'list', // Ordered/unordered lists
'justify', // Text alignment
'quote', // Blockquote
'emoticon', // Emoticons/emojis
'image', // Image insertion
'table', // Table insertion
'video', // Video embedding
'code', // Code blocks
'undo', // Undo action
'redo' // Redo action
];Usage Examples:
// Minimal toolbar
editor.customConfig.menus = ['bold', 'italic', 'underline'];
// Common formatting options
editor.customConfig.menus = [
'head', 'bold', 'italic', 'underline', 'foreColor', 'backColor'
];
// Full featured editor
editor.customConfig.menus = [
'head', 'bold', 'fontSize', 'fontName', 'italic', 'underline',
'strikeThrough', 'foreColor', 'backColor', 'link', 'list',
'justify', 'quote', 'emoticon', 'image', 'table', 'video',
'code', 'undo', 'redo'
];Configure available fonts and font sizes.
interface FontConfig {
/** Array of font family names available in font dropdown */
fontNames?: string[];
}Usage Examples:
// Default fonts
editor.customConfig.fontNames = [
'宋体',
'微软雅黑',
'Arial',
'Tahoma',
'Verdana'
];
// Custom font list
editor.customConfig.fontNames = [
'Arial',
'Helvetica',
'Times New Roman',
'Georgia',
'Courier New'
];
// Web fonts
editor.customConfig.fontNames = [
'system-ui',
'Roboto',
'Open Sans',
'Lato',
'Montserrat'
];Define color palettes for text and background colors.
interface ColorConfig {
/** Array of color values available in color pickers */
colors?: string[];
}Usage Examples:
// Custom color palette
editor.customConfig.colors = [
'#000000', '#333333', '#666666', '#999999', '#cccccc', '#ffffff',
'#ff0000', '#ff9900', '#ffff00', '#00ff00', '#00ffff', '#0000ff',
'#9900ff', '#ff0099'
];
// Brand colors
editor.customConfig.colors = [
'#1f2937', // Dark gray
'#3b82f6', // Blue
'#10b981', // Green
'#f59e0b', // Yellow
'#ef4444', // Red
'#8b5cf6', // Purple
'#f97316', // Orange
'#06b6d4' // Cyan
];Configure callbacks for editor events.
interface EventConfig {
/** Callback fired when content changes */
onchange?: (html: string) => void;
/** Callback fired when editor loses focus */
onblur?: (html: string) => void;
/** Callback fired when editor gains focus */
onfocus?: () => void;
/** Debounce timeout for onchange event in milliseconds */
onchangeTimeout?: number;
}Usage Examples:
// Content change handling
editor.customConfig.onchange = function(html) {
console.log('Content changed:', html);
// Auto-save, validation, etc.
};
// Focus/blur handling
editor.customConfig.onfocus = function() {
console.log('Editor focused');
document.getElementById('editor-status').textContent = 'Editing...';
};
editor.customConfig.onblur = function(html) {
console.log('Editor blurred');
document.getElementById('editor-status').textContent = 'Saved';
saveContent(html);
};
// Debounced change events
editor.customConfig.onchangeTimeout = 500; // 500ms delay
editor.customConfig.onchange = function(html) {
// This will only fire 500ms after user stops typing
performExpensiveOperation(html);
};Control editor appearance and behavior.
interface UIConfig {
/** Z-index for editor UI elements */
zIndex?: number;
/** Enable debug mode with error throwing */
debug?: boolean;
/** Language configuration for UI text */
lang?: {[key: string]: string};
/** Custom alert function for messages */
customAlert?: (info: string) => void;
}Usage Examples:
// Z-index configuration
editor.customConfig.zIndex = 15000; // Ensure editor appears above other elements
// Debug mode
editor.customConfig.debug = true; // Throw errors instead of silent failure
// Custom alert
editor.customConfig.customAlert = function(info) {
// Use custom modal instead of browser alert
showCustomModal(info);
};
// Language customization
editor.customConfig.lang = {
'设置标题': 'Set Title',
'正文': 'Normal',
'链接文字': 'Link Text',
'链接': 'URL'
};Control paste behavior and content filtering.
interface PasteConfig {
/** Filter styles when pasting content */
pasteFilterStyle?: boolean;
/** Ignore images when pasting */
pasteIgnoreImg?: boolean;
/** Custom handler for processing pasted content */
pasteTextHandle?: (content: string) => string;
}Usage Examples:
// Basic paste filtering
editor.customConfig.pasteFilterStyle = true; // Remove inline styles
editor.customConfig.pasteIgnoreImg = false; // Allow pasted images
// Custom paste processing
editor.customConfig.pasteTextHandle = function(content) {
// Custom content processing
content = content.replace(/\n/g, '<br>'); // Convert line breaks
content = content.replace(/\t/g, ' '); // Convert tabs
return content;
};
// Advanced paste filtering
editor.customConfig.pasteTextHandle = function(content) {
// Remove unwanted HTML tags
const allowedTags = ['p', 'br', 'strong', 'em', 'u', 'h1', 'h2', 'h3'];
const doc = new DOMParser().parseFromString(content, 'text/html');
// Filter content based on allowed tags
const walker = document.createTreeWalker(
doc.body,
NodeFilter.SHOW_ELEMENT,
{
acceptNode: function(node) {
return allowedTags.includes(node.tagName.toLowerCase())
? NodeFilter.FILTER_ACCEPT
: NodeFilter.FILTER_REJECT;
}
}
);
// Process and return filtered content
return doc.body.innerHTML;
};Configure link insertion and validation.
interface LinkConfig {
/** Validation function for inserted links */
linkCheck?: (text: string, link: string) => boolean | string;
/** Validation function for network images */
linkImgCheck?: (src: string) => boolean | string;
/** Show network image insertion tab */
showLinkImg?: boolean;
/** Callback when network image is inserted */
linkImgCallback?: (url: string) => void;
}Usage Examples:
// Link validation
editor.customConfig.linkCheck = function(text, link) {
// Return true for valid links, string for error message
if (!link.startsWith('http://') && !link.startsWith('https://')) {
return 'Links must start with http:// or https://';
}
if (link.includes('malicious-site.com')) {
return 'This domain is not allowed';
}
return true; // Valid link
};
// Image link validation
editor.customConfig.linkImgCheck = function(src) {
const allowedDomains = ['example.com', 'images.example.com'];
const url = new URL(src);
if (!allowedDomains.includes(url.hostname)) {
return 'Images must be from allowed domains';
}
return true;
};
// Network image configuration
editor.customConfig.showLinkImg = true;
editor.customConfig.linkImgCallback = function(url) {
console.log('Network image inserted:', url);
// Track image usage, validate, etc.
};Configure available emoticons and emojis.
interface EmoticonConfig {
/** Emoticon configuration with tabs and content */
emotions?: Array<{
title: string;
type: 'image' | 'emoji';
content: Array<{
alt: string;
src?: string;
data?: string;
}>;
}>;
}Usage Examples:
// Custom emoticons
editor.customConfig.emotions = [
{
title: 'Smileys',
type: 'emoji',
content: [
{alt: '[smile]', data: '😊'},
{alt: '[laugh]', data: '😂'},
{alt: '[sad]', data: '😢'},
{alt: '[angry]', data: '😠'}
]
},
{
title: 'Custom',
type: 'image',
content: [
{alt: '[custom1]', src: '/images/emoji1.png'},
{alt: '[custom2]', src: '/images/emoji2.png'}
]
}
];
// Simple emoji set
editor.customConfig.emotions = [
{
title: 'Basic',
type: 'emoji',
content: [
{alt: '😊', data: '😊'},
{alt: '😂', data: '😂'},
{alt: '🤔', data: '🤔'},
{alt: '👍', data: '👍'},
{alt: '❤️', data: '❤️'}
]
}
];interface CustomConfig {
// Menu configuration
menus?: string[];
fontNames?: string[];
colors?: string[];
emotions?: Array<any>;
// UI configuration
zIndex?: number;
debug?: boolean;
lang?: {[key: string]: string};
customAlert?: (info: string) => void;
// Event handlers
onchange?: (html: string) => void;
onblur?: (html: string) => void;
onfocus?: () => void;
onchangeTimeout?: number;
// Paste configuration
pasteFilterStyle?: boolean;
pasteIgnoreImg?: boolean;
pasteTextHandle?: (content: string) => string;
// Link configuration
linkCheck?: (text: string, link: string) => boolean | string;
linkImgCheck?: (src: string) => boolean | string;
showLinkImg?: boolean;
linkImgCallback?: (url: string) => void;
// Upload configuration (see Image Upload documentation)
uploadImgServer?: string;
uploadImgMaxSize?: number;
uploadImgMaxLength?: number;
uploadImgShowBase64?: boolean;
uploadFileName?: string;
uploadImgParams?: {[key: string]: any};
uploadImgParamsWithUrl?: boolean;
uploadImgHeaders?: {[key: string]: string};
withCredentials?: boolean;
uploadImgTimeout?: number;
uploadImgHooks?: {[key: string]: Function};
qiniu?: boolean;
customUploadImg?: (files: FileList, insert: Function) => void;
}// Different configs for different environments
function createEditorConfig(environment) {
const baseConfig = {
zIndex: 10000,
pasteFilterStyle: true,
onchangeTimeout: 200
};
const configs = {
development: {
...baseConfig,
debug: true,
customAlert: console.log
},
production: {
...baseConfig,
debug: false,
customAlert: function(info) {
// Log to monitoring service
logToService('editor-alert', info);
}
}
};
return configs[environment] || configs.production;
}
// Usage
const config = createEditorConfig(process.env.NODE_ENV);
Object.assign(editor.customConfig, config);// Configuration presets for different use cases
const EditorPresets = {
minimal: {
menus: ['bold', 'italic'],
colors: ['#000000', '#ff0000', '#0000ff']
},
blog: {
menus: ['head', 'bold', 'italic', 'underline', 'foreColor', 'link', 'image'],
pasteFilterStyle: true,
linkCheck: function(text, link) {
return link.startsWith('http://') || link.startsWith('https://');
}
},
comment: {
menus: ['bold', 'italic', 'emoticon'],
emotions: [/* emoji set */],
uploadImgServer: '/api/upload'
},
full: {
menus: [
'head', 'bold', 'fontSize', 'fontName', 'italic', 'underline',
'strikeThrough', 'foreColor', 'backColor', 'link', 'list',
'justify', 'quote', 'emoticon', 'image', 'table', 'video',
'code', 'undo', 'redo'
]
}
};
// Apply preset
Object.assign(editor.customConfig, EditorPresets.blog);Install with Tessl CLI
npx tessl i tessl/npm-wangeditor