Editor.js Integration into CMS
Editor.js is a block editor with clean JSON output. Each paragraph, heading, image—separate block with typed data. This makes content structured and portable between platforms.
Installation
npm install @editorjs/editorjs @editorjs/paragraph @editorjs/header @editorjs/image
npm install @editorjs/list @editorjs/quote @editorjs/code @editorjs/table
Initialization
import EditorJS from '@editorjs/editorjs';
import Header from '@editorjs/header';
import Image from '@editorjs/image';
import List from '@editorjs/list';
const editor = new EditorJS({
holder: 'editor-container',
placeholder: 'Start typing content...',
tools: {
header: {
class: Header,
config: { levels: [2, 3, 4], defaultLevel: 2 }
},
image: {
class: Image,
config: {
uploader: {
uploadByFile: async (file) => {
const formData = new FormData();
formData.append('image', file);
const response = await fetch('/api/media/upload', {
method: 'POST', body: formData
});
const data = await response.json();
return { success: 1, file: { url: data.url } };
}
}
}
},
list: { class: List, inlineToolbar: true },
quote: { class: Quote, inlineToolbar: true }
},
data: initialData // JSON from database
});
// Save
const savedData = await editor.save();
// savedData.blocks — array of blocks
Data Format
{
"time": 1710500000000,
"blocks": [
{ "type": "header", "data": { "text": "Article heading", "level": 2 } },
{ "type": "paragraph", "data": { "text": "Paragraph text <b>with formatting</b>." } },
{ "type": "image", "data": { "file": { "url": "/uploads/photo.jpg" }, "caption": "Caption" } },
{ "type": "list", "data": { "style": "ordered", "items": ["First", "Second"] } }
]
}
Server-side Rendering JSON
For SSR or server-side HTML generation from Editor.js JSON:
// PHP: convert Editor.js JSON → HTML
class EditorJsRenderer
{
public function render(array $data): string
{
return collect($data['blocks'])->map(fn($block) =>
match($block['type']) {
'header' => "<h{$block['data']['level']}>{$block['data']['text']}</h{$block['data']['level']}>",
'paragraph' => "<p>{$block['data']['text']}</p>",
'image' => "<figure><img src=\"{$block['data']['file']['url']}\" alt=\"{$block['data']['caption']}\"><figcaption>{$block['data']['caption']}</figcaption></figure>",
'list' => $this->renderList($block['data']),
'quote' => "<blockquote>{$block['data']['text']}<cite>{$block['data']['caption']}</cite></blockquote>",
default => ''
}
)->implode("\n");
}
}
Custom Tool
class CalloutBlock {
static get toolbox() {
return { title: 'Callout', icon: '<svg>...</svg>' };
}
render() {
this.wrapper = document.createElement('div');
this.wrapper.className = 'callout-block';
this.wrapper.contentEditable = true;
return this.wrapper;
}
save(element) {
return { text: element.innerHTML };
}
}
Integration timeline: 1–2 days for basic editor with image upload and server-side rendering.







