Source Plugin
- Features
- sourceEditor
- sourceEditorNativeOptions
- beautifyHTML
- beautifyHTMLCDNUrlsJS
- sourceEditorCDNUrlsJS
- source Control
- Basic Usage with Ace Editor
- Use Plain Textarea
- Custom Ace Theme
- Disable HTML Beautification
- Custom CodeMirror Editor
- Programmatic Mode Switch
- Insert HTML in Source Mode
- Select All in Source Mode
- Listen to Source Editor Ready
- Custom Beautify Function
- Initialization
- Editor Factory
- Mode Switching
- Selection Preservation
- Position Normalization
- Value Synchronization
- Auto-sync Triggers
- HTML Beautification
- Insert HTML in Source Mode
- Ace Editor Loading
- Readonly Synchronization
- sourceEditorReady
- placeholder
- beautifyHTML
- insertHTML
- selectall
- ISourceEditor Interface
- Edge Cases
- Notes
- Typical Use Case
- Classes
Provides HTML source code editing mode using external code editors. This plugin allows users to switch between WYSIWYG and source code editing modes, with support for Ace Editor (default), plain textarea, or custom editor implementations.
Features
- Toggle between WYSIWYG and source code modes
- Ace Editor integration via CDN
- Plain textarea fallback
- Custom editor implementation support
- Selection preservation across mode switches
- HTML beautification support
- Read-only mode synchronization
- ESC key to blur source editor
- Split mode support (WYSIWYG + source)
- Selection markers for cursor restoration
- Insert HTML in source mode
- Select all command in source mode
- Auto-sync between WYSIWYG and source
- Touch-friendly mode switching
- Shadow DOM fallback to textarea
sourceEditor
Type: 'area' | 'ace' | ((jodit: IJodit) => ISourceEditor)
Default: 'ace'
Determines which source code editor to use:
'ace'
: Ace Editor loaded from CDN (default)'area'
: Plain textarea- Custom function: Returns custom editor implementation
Example:
// Use Ace Editor (default)
const editor1 = Jodit.make('#editor1', {
sourceEditor: 'ace'
});
// Use plain textarea
const editor2 = Jodit.make('#editor2', {
sourceEditor: 'area'
});
// Use custom editor (CodeMirror example)
const editor3 = Jodit.make('#editor3', {
sourceEditor: (jodit) => new MyCodeMirrorEditor(jodit)
});
sourceEditorNativeOptions
Type: object
Default:
{
showGutter: true,
theme: 'ace/theme/idle_fingers',
mode: 'ace/mode/html',
wrap: true,
highlightActiveLine: true
}
Configuration options passed directly to Ace Editor. See Ace Editor docs for all options.
Properties:
showGutter
(boolean): Show line numbers in guttertheme
(string): Ace theme name (e.g., 'ace/theme/chrome')mode
(string): Syntax highlighting mode (e.g., 'ace/mode/html')wrap
(string | boolean | number): Line wrapping - "off", 80-100, true, "free"highlightActiveLine
(boolean): Highlight current line
Example:
const editor = Jodit.make('#editor', {
sourceEditorNativeOptions: {
showGutter: true,
theme: 'ace/theme/chrome', // Light theme
mode: 'ace/mode/html',
wrap: 'free', // Free wrap
highlightActiveLine: false
}
});
beautifyHTML
Type: boolean
Default: true
(false in IE)
When enabled, beautifies HTML code in source mode using js-beautify library loaded from CDN. Improves code readability with proper indentation and formatting.
Example:
const editor = Jodit.make('#editor', {
beautifyHTML: true
});
// HTML will be auto-formatted when switching to source mode
beautifyHTMLCDNUrlsJS
Type: string[]
Default:
[
'https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.4/beautify.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.4/beautify-html.min.js'
]
CDN URLs for loading js-beautify library when beautifyHTML
is enabled.
Example:
const editor = Jodit.make('#editor', {
beautifyHTML: true,
beautifyHTMLCDNUrlsJS: [
'https://my-cdn.com/beautify.min.js',
'https://my-cdn.com/beautify-html.min.js'
]
});
sourceEditorCDNUrlsJS
Type: string[]
Default:
[
'https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.2/ace.js'
]
CDN URLs for loading Ace Editor when sourceEditor: 'ace'
.
Example:
const editor = Jodit.make('#editor', {
sourceEditor: 'ace',
sourceEditorCDNUrlsJS: [
'https://my-cdn.com/ace.js'
]
});
source
Control
Icon: 'source'
Tooltip: 'Change mode'
Group: 'source'
Mode: MODE_SPLIT
Toggles editor mode between WYSIWYG and source code editing.
Basic Usage with Ace Editor
const editor = Jodit.make('#editor', {
sourceEditor: 'ace'
});
// Click Source button in toolbar to toggle mode
// Editor loads Ace from CDN and displays HTML source
Use Plain Textarea
const editor = Jodit.make('#editor', {
sourceEditor: 'area'
});
// Simple textarea for source editing
// No external dependencies
Custom Ace Theme
const editor = Jodit.make('#editor', {
sourceEditor: 'ace',
sourceEditorNativeOptions: {
theme: 'ace/theme/chrome', // Light Chrome theme
showGutter: true,
highlightActiveLine: true,
wrap: 80 // Wrap at 80 chars
}
});
// See https://ace.c9.io/build/kitchen-sink.html for theme list
Disable HTML Beautification
const editor = Jodit.make('#editor', {
beautifyHTML: false
});
// HTML displayed exactly as stored, no formatting
Custom CodeMirror Editor
class CodeMirrorEditor {
constructor(jodit) {
this.jodit = jodit;
this.mirror = CodeMirror(/* ... */);
}
getValue() {
return this.mirror.getValue();
}
setValue(raw) {
this.mirror.setValue(raw);
}
insertRaw(raw) {
this.mirror.replaceSelection(raw);
}
getSelectionStart() {
const cursor = this.mirror.getCursor('start');
return this.mirror.indexFromPos(cursor);
}
getSelectionEnd() {
const cursor = this.mirror.getCursor('end');
return this.mirror.indexFromPos(cursor);
}
setSelectionRange(start, end) {
const startPos = this.mirror.posFromIndex(start);
const endPos = this.mirror.posFromIndex(end);
this.mirror.setSelection(startPos, endPos);
}
setPlaceHolder(title) {
this.mirror.setOption('placeholder', title);
}
focus() {
this.mirror.focus();
}
setReadOnly(isReadOnly) {
this.mirror.setOption('readOnly', isReadOnly);
}
selectAll() {
this.mirror.execCommand('selectAll');
}
get isReady() {
return true;
}
onReadyAlways(callback) {
callback();
}
}
const editor = Jodit.make('#editor', {
sourceEditor: (jodit) => new CodeMirrorEditor(jodit)
});
Programmatic Mode Switch
const editor = Jodit.make('#editor');
// Toggle to source mode
editor.toggleMode();
// Or use setMode
editor.setMode(Jodit.constants.MODE_SOURCE);
// Back to WYSIWYG
editor.setMode(Jodit.constants.MODE_WYSIWYG);
// Split mode (both visible)
editor.setMode(Jodit.constants.MODE_SPLIT);
Insert HTML in Source Mode
const editor = Jodit.make('#editor');
editor.setMode(Jodit.constants.MODE_SOURCE);
// Insert HTML at cursor position
editor.e.fire('insertHTML', '<strong>Bold text</strong>');
// Automatically updates WYSIWYG view
Select All in Source Mode
const editor = Jodit.make('#editor');
editor.setMode(Jodit.constants.MODE_SOURCE);
// Select all source code
editor.execCommand('selectall');
Listen to Source Editor Ready
const editor = Jodit.make('#editor');
editor.e.on('sourceEditorReady', () => {
console.log('Source editor initialized and ready');
});
Custom Beautify Function
const editor = Jodit.make('#editor', {
beautifyHTML: true
});
editor.e.on('beautifyHTML', (html) => {
// Custom beautification logic
return html.replace(/></g, '>\n<');
});
Initialization
On plugin init:
- Creates
.jodit-source
container in workplace - Creates initial textarea editor (default)
- Attaches ESC key handler to blur source editor
- Sets up placeholder, change, beautifyHTML events
- If
sourceEditor !== 'area'
, loads external editor (Ace) - When editor ready, replaces textarea with external editor
- Fires
sourceEditorReady
event
Editor Factory
The createSourceEditor()
factory:
- If
sourceEditor
is function: calls it to get custom editor - If
sourceEditor === 'ace'
and no shadow root: createsAceEditor
- Otherwise: creates
TextAreaEditor
(fallback) - Calls
init()
andsetReadOnly()
on editor - Returns
ISourceEditor
implementation
Mode Switching
When user clicks Source button or calls toggleMode()
:
Before Mode Switch (beforeSetMode
event):
- From WYSIWYG: Saves selection, syncs value, updates source via
fromWYSIWYG()
- From Source: Inserts selection markers at cursor position, converts to WYSIWYG
After Mode Switch (afterSetMode
event):
- To WYSIWYG: Restores selection from saved state
- To Source: Finds selection markers in HTML, removes them, sets cursor position
Selection Preservation
When switching from source to WYSIWYG:
- Gets cursor/selection from source editor
- Normalizes position to avoid splitting tags
- Inserts
<span data-jodit-selection_marker="start">
marker - If range selection, inserts end marker too
- Converts source to WYSIWYG via
toWYSIWYG()
- Markers replaced with temp strings:
{start-jodit-selection}
,{end-jodit-selection}
- If beautifyHTML enabled, beautifies while preserving markers
- Finds marker positions in beautified HTML
- Removes markers from HTML
- Sets selection range in source editor at marker positions
When switching from WYSIWYG to source:
- Calls
editor.s.save()
to insert DOM selection markers - Syncs WYSIWYG value to editor
- Updates source via
fromWYSIWYG(true)
(force) - On
afterSetMode
, callseditor.s.restore()
to restore selection in WYSIWYG
Position Normalization
The getNormalPosition()
method:
- Adjusts cursor position to avoid splitting HTML tags
- Replaces script/style/iframe content with invisible spaces for calculation
- Walks backward from position to find safe insertion point
- Returns position after
>
or before<
to avoid tag corruption
Value Synchronization
fromWYSIWYG(): WYSIWYG → Source
- Gets editor value via
getEditorValue(false, SOURCE_CONSUMER)
- Compares with current source value
- Updates source editor if different
- Uses lock flag to prevent circular updates
toWYSIWYG(): Source → WYSIWYG
- Gets value from source editor
- Compares with old value
- Sets
editor.value = sourceValue
- Updates old value cache
- Uses lock flag to prevent circular updates
Auto-sync Triggers
Source editor synced from WYSIWYG on:
change
event (user edits WYSIWYG)- Mode switch to
MODE_SOURCE
orMODE_SPLIT
sourceEditorReady
event
WYSIWYG synced from source on:
- Source editor value change (via source editor onChange)
- Mode switch from source to WYSIWYG
HTML Beautification
When beautifyHTML: true
:
- Loads js-beautify from
beautifyHTMLCDNUrlsJS
on init - When loaded, registers
beautifyHTML
event handler - On mode switch to source, fires
beautifyHTML
event with HTML - Event handler calls
html_beautify(html)
from loaded library - Returns formatted HTML
- Formatted HTML displayed in source editor
Insert HTML in Source Mode
When insertHTML
event fired in source mode:
- Calls
sourceEditor.insertRaw(html)
to insert at cursor - Calls
toWYSIWYG()
to sync WYSIWYG view - Returns
false
to prevent default insertion
Ace Editor Loading
For sourceEditor: 'ace'
:
- Creates
AceEditor
instance (loads ace.js from CDN if needed) - Applies
sourceEditorNativeOptions
to Ace instance - Sets up onChange handler to call
toWYSIWYG()
- Calls
onReadyAlways()
callback when loaded - Replaces initial textarea editor with Ace editor
Readonly Synchronization
When readonly
option changes:
onReadonlyReact()
called via@watch(':readonly.source')
- Calls
sourceEditor.setReadOnly(editor.o.readonly)
- Source editor reflects readonly state
sourceEditorReady
Fired when source editor (Ace or custom) is fully initialized and ready.
Parameters:
editor
(IJodit): The editor instance
Example:
editor.e.on('sourceEditorReady', (editor) => {
console.log('Source editor ready');
});
placeholder
Plugin listens to this event to set placeholder text in source editor.
Parameters:
text
(string): Placeholder text
Example:
editor.e.fire('placeholder', 'Enter HTML here...');
beautifyHTML
Fired to beautify HTML code. Plugin uses this event to format HTML via js-beautify.
Parameters:
html
(string): HTML to beautify
Returns: Formatted HTML string
Example:
editor.e.on('beautifyHTML', (html) => {
// Custom formatting
return myBeautifyFunction(html);
});
insertHTML
Plugin intercepts this event in source mode to insert HTML at cursor position.
Parameters:
html
(string): HTML to insert
Example:
editor.e.fire('insertHTML', '<p>New paragraph</p>');
selectall
Plugin intercepts this command in source mode to select all source code.
Example:
editor.execCommand('selectall');
// Selects all text in source editor
ISourceEditor Interface
Custom editors must implement this interface:
Methods:
getValue(): string
- Get current source codesetValue(raw: string): void
- Set source codeinsertRaw(raw: string): void
- Insert HTML at cursorgetSelectionStart(): number
- Get selection start positiongetSelectionEnd(): number
- Get selection end positionsetSelectionRange(start: number, end: number): void
- Set selection rangesetPlaceHolder(title: string): void
- Set placeholder textfocus(): void
- Focus the editorsetReadOnly(isReadOnly: boolean): void
- Set readonly stateselectAll(): void
- Select all content
Properties:
isReady: boolean
- Whether editor is initializedisFocused: boolean
- Whether editor has focus
Lifecycle:
init(jodit: IJodit): void
- Initialize editoronReadyAlways(callback: Function): void
- Call callback when readydestruct(): void
- Cleanup on destroyblur(): void
- Remove focus
Edge Cases
- Shadow DOM: Falls back to textarea when shadow root detected (Ace incompatible)
- IE Browser:
beautifyHTML
defaults to false (performance) - ESC Key: Blurs source editor when ESC pressed in source mode
- Lock Flag: Prevents circular updates between WYSIWYG and source
- Selection in Tags: Normalized to avoid splitting tags during mode switch
- Invisible Spaces: Used for position calculation in script/style/iframe tags
- Beautify Failure: Silently falls back to unformatted HTML
- CDN Load Failure: Textarea used if Ace fails to load
- Mode Switch: Selection preserved across WYSIWYG ↔ source transitions
- Read-only Mode: Synchronized to source editor
Notes
- Plugin is class-based, extends
Plugin
base class - Uses
@autobind
and@watch
decorators - Source button in 'source' toolbar group
- Event namespacing
.source
for clean removal - Lock flag
__lock
prevents circular sync - Old value cache
__oldMirrorValue
for change detection - Selection markers:
{start-jodit-selection}
,{end-jodit-selection}
- Marker regex:
tempMarkerStartReg
,tempMarkerEndReg
- The
mirrorContainer
holds source editor - Ace Editor theme list: https://ace.c9.io/build/kitchen-sink.html
- Ace mode for HTML:
ace/mode/html
- Default Ace theme:
ace/theme/idle_fingers
(dark) - Beautify library: js-beautify from cdnjs
- The
SOURCE_CONSUMER
constant identifies source mode requests - Position normalization uses
INVISIBLE_SPACE
character - ESC key handler attached to owner window
- The
createSourceEditor()
factory creates editor instances - AceEditor and TextAreaEditor in
./editor/engines/
- The plugin properly cleans up source editor on destruction
- Selection saved before mode switch, restored after
- Split mode shows both WYSIWYG and source simultaneously
- The
getNormalPosition()
prevents cursor in middle of tags - Beautify event allows custom formatting logic
- Source editor container class:
jodit-source
- The
controls.source
defines toolbar button behavior - Default mode is
MODE_SPLIT
(shows both editors) - The
isActive
function checks if source mode active - Placeholder text forwarded to source editor
- Change event triggers sync from WYSIWYG to source
Typical Use Case
Developers and power users need direct HTML access for precise control, debugging, or copying code. The source plugin provides this by:
- Adding Source button to toggle HTML editing mode
- Loading professional code editor (Ace) with syntax highlighting
- Preserving cursor position when switching between modes
- Auto-formatting HTML for readability (beautifyHTML)
- Supporting custom editor implementations (CodeMirror, Monaco, etc.)
This improves user experience by:
- Providing familiar code editor interface
- Syntax highlighting for easier reading
- Line numbers and code folding
- Maintaining selection across mode switches
- Supporting both simple (textarea) and advanced (Ace) editors
- Allowing full HTML control when needed
Classes
createSourceEditor
createSourceEditor(type
, editor
, container
, toWYSIWYG
, fromWYSIWYG
): ISourceEditor
Parameters
Name | Type |
---|---|
type |
"area" | "ace" | "mirror" | (jodit : IJodit ) => ISourceEditor |
editor |
IJodit |
container |
HTMLElement |
toWYSIWYG |
CallbackFunction <any > |
fromWYSIWYG |
CallbackFunction <any > |
Returns
Defined in
jodit/src/plugins/source/editor/factory.ts:16