Editor.js is a modern, block-style WYSIWYG text editor that outputs clean JSON data instead of heavy HTML markup. It features a modular architecture where each content block (text, images, lists, quotes, etc.) is provided via separate plugins, making it extremely flexible and extensible for web applications, mobile apps, and other platforms.
npm install @editorjs/editorjsimport EditorJS from '@editorjs/editorjs';For CommonJS:
const EditorJS = require('@editorjs/editorjs');You can also import types for TypeScript development:
import EditorJS, {
EditorConfig,
OutputData,
API,
BlockTool,
InlineTool,
BlockAPI
} from '@editorjs/editorjs';import EditorJS from '@editorjs/editorjs';
// Create editor instance
const editor = new EditorJS({
holder: 'editorjs', // HTML element ID
autofocus: true,
placeholder: 'Start writing your story...',
tools: {
// Add tools as needed
}
});
// Wait for editor to be ready
await editor.isReady;
// Save data
const outputData = await editor.save();
console.log('Article data:', outputData);
// Load data
await editor.render({
blocks: [
{
type: "paragraph",
data: {
text: "Hello, World!"
}
}
]
});
// Focus editor
editor.focus();
// Clear all blocks
editor.clear();
// Destroy editor instance
editor.destroy();Editor.js is built around several key architectural components:
Main EditorJS class providing the primary interface for creating and managing editor instances.
class EditorJS {
static readonly version: string;
readonly isReady: Promise<void>;
constructor(configuration?: EditorConfig | string);
// Data operations
save(): Promise<OutputData>;
render(data: OutputData): Promise<void>;
clear(): void;
// Focus and interaction
focus(atEnd?: boolean): boolean;
// Event system
on(eventName: string, callback: (data?: any) => void): void;
off(eventName: string, callback: (data?: any) => void): void;
emit(eventName: string, data: any): void;
// Lifecycle
destroy(): void;
}Comprehensive API for manipulating editor blocks including insertion, deletion, movement, and transformation.
interface Blocks {
// Content operations
clear(): Promise<void>;
render(data: OutputData): Promise<void>;
renderFromHTML(data: string): Promise<void>;
// Block manipulation
insert(type?: string, data?: BlockToolData, config?: ToolConfig,
index?: number, needToFocus?: boolean, replace?: boolean,
id?: string): BlockAPI;
insertMany(blocks: OutputBlockData[], index?: number): BlockAPI[];
delete(index?: number): void;
move(toIndex: number, fromIndex?: number): void;
// Block access
getBlockByIndex(index: number): BlockAPI | undefined;
getById(id: string): BlockAPI | null;
getCurrentBlockIndex(): number;
getBlocksCount(): number;
// Block operations
update(id: string, data?: Partial<BlockToolData>,
tunes?: {[name: string]: BlockTuneData}): Promise<BlockAPI>;
convert(id: string, newType: string,
dataOverrides?: BlockToolData): Promise<BlockAPI>;
}Precise caret positioning and navigation throughout the editor blocks.
interface Caret {
// Position setting
setToFirstBlock(position?: 'end'|'start'|'default', offset?: number): boolean;
setToLastBlock(position?: 'end'|'start'|'default', offset?: number): boolean;
setToPreviousBlock(position?: 'end'|'start'|'default', offset?: number): boolean;
setToNextBlock(position?: 'end'|'start'|'default', offset?: number): boolean;
setToBlock(blockOrIdOrIndex: BlockAPI | string | number,
position?: 'end'|'start'|'default', offset?: number): boolean;
// Focus control
focus(atEnd?: boolean): boolean;
}Robust event system for subscribing to editor changes and user interactions.
interface Events {
emit(eventName: string, data: any): void;
off(eventName: string, callback: (data?: any) => void): void;
on(eventName: string, callback: (data?: any) => void): void;
}Complete interfaces and types for developing Block Tools, Inline Tools, and Block Tunes.
interface BlockTool {
render(): HTMLElement;
save(block: HTMLElement): BlockToolData;
sanitize?: SanitizerConfig;
renderSettings?(): HTMLElement | MenuConfig;
validate?(blockData: BlockToolData): boolean;
merge?(blockData: BlockToolData): void;
onPaste?(event: PasteEvent): void;
destroy?(): void;
// Lifecycle hooks
rendered?(): void;
updated?(): void;
removed?(): void;
moved?(event: MoveEvent): void;
}
interface InlineTool {
render(): HTMLElement | MenuConfig;
shortcut?: string;
surround?(range: Range | null): void;
checkState?(selection: Selection): boolean;
renderActions?(): HTMLElement;
clear?(): void;
}Comprehensive configuration options for editor behavior, tools, and appearance.
interface EditorConfig {
// Basic setup
holder?: string | HTMLElement;
autofocus?: boolean;
defaultBlock?: string;
placeholder?: string | false;
// Tools and functionality
tools?: {[toolName: string]: ToolConstructable | ToolSettings};
data?: OutputData;
sanitizer?: SanitizerConfig;
// Behavior
readOnly?: boolean;
hideToolbar?: boolean;
minHeight?: number;
logLevel?: LogLevels;
// Internationalization
i18n?: I18nConfig;
// Events
onReady?(): void;
onChange?(api: API, event: BlockMutationEvent | BlockMutationEvent[]): void;
// Styling
inlineToolbar?: string[] | boolean;
tunes?: string[];
style?: { nonce?: string };
}interface OutputData {
version?: string;
time?: number;
blocks: OutputBlockData[];
}
interface OutputBlockData<Type extends string = string, Data extends object = any> {
id?: string;
type: Type;
data: BlockToolData<Data>;
tunes?: {[name: string]: BlockTuneData};
}
interface API {
blocks: Blocks;
caret: Caret;
tools: Tools;
events: Events;
listeners: Listeners;
notifier: Notifier;
sanitizer: Sanitizer;
saver: Saver;
selection: Selection;
styles: Styles;
toolbar: Toolbar;
inlineToolbar: InlineToolbar;
tooltip: Tooltip;
i18n: I18n;
readOnly: ReadOnly;
ui: Ui;
}
interface BlockAPI {
readonly id: string;
readonly name: string;
readonly config: ToolConfig;
readonly holder: HTMLElement;
readonly isEmpty: boolean;
readonly selected: boolean;
readonly focusable: boolean;
stretched: boolean;
call(methodName: string, param?: object): void;
save(): Promise<void | SavedData>;
validate(data: BlockToolData): Promise<boolean>;
dispatchChange(): void;
getActiveToolboxEntry(): Promise<ToolboxConfigEntry | undefined>;
}
interface Saver {
save(): Promise<OutputData>;
}
interface Sanitizer {
clean(taintString: string, config: SanitizerConfig): string;
}
interface Notifier {
show(options: NotifierOptions | ConfirmNotifierOptions | PromptNotifierOptions): void;
}
interface Tools {
getBlockTools(): BlockToolAdapter[];
}
interface Listeners {
on(element: Element, eventType: string, handler: (event?: Event) => void, useCapture?: boolean): string;
off(element: Element, eventType: string, handler: (event?: Event) => void, useCapture?: boolean): void;
offById(id: string): void;
}
interface Selection {
findParentTag(tagName: string, className?: string): HTMLElement | null;
expandToTag(node: HTMLElement): void;
setFakeBackground(): void;
removeFakeBackground(): void;
save(): void;
restore(): void;
}
interface Styles {
block: string;
inlineToolButton: string;
inlineToolButtonActive: string;
input: string;
loader: string;
settingsButton: string;
settingsButtonActive: string;
button: string;
}
interface Toolbar {
close(): void;
open(): void;
toggleBlockSettings(openingState?: boolean): void;
toggleToolbox(openingState?: boolean): void;
}
interface InlineToolbar {
close(): void;
open(): void;
}
interface Tooltip {
show(element: HTMLElement, content: TooltipContent, options?: TooltipOptions): void;
hide(): void;
onHover(element: HTMLElement, content: TooltipContent, options?: TooltipOptions): void;
}
interface I18n {
t(dictKey: string): string;
}
interface ReadOnly {
toggle(state?: boolean): Promise<boolean>;
isEnabled: boolean;
}
interface Ui {
nodes: UiNodes;
}
interface UiNodes {
wrapper: HTMLElement;
redactor: HTMLElement;
}
// External types from dependencies
interface NotifierOptions {
[key: string]: any;
}
interface ConfirmNotifierOptions {
[key: string]: any;
}
interface PromptNotifierOptions {
[key: string]: any;
}
interface TooltipContent {
[key: string]: any;
}
interface TooltipOptions {
[key: string]: any;
}
interface BlockToolAdapter {
[key: string]: any;
}
interface SanitizerConfig {
[key: string]: any;
}