Editor.js is a block-based editor that outputs clean JSON, but integrating it into a CMS requires a well-thought-out architecture. Without the right approach, developers face hydration issues during SSR, image upload complexities, and non-obvious save errors. Our team has over 5 years of experience with block editors, having completed 50+ projects. We've accumulated proven solutions and are ready to share a reliable integration method for Editor.js integration, including custom block editor tools, image upload, and server-side JSON rendering in PHP. Below is the full integration cycle: installation, configuration, server-side rendering, and typical use cases. If you need to speed up the process, we handle the entire integration turnkey, with a guaranteed 30-day support period.
Editor.js Advantages Over Classic WYSIWYG Editors
WYSIWYG editors (TinyMCE, Quill) generate HTML markup that is hard to parse and transfer between systems. Editor.js works differently: each paragraph, heading, or image is a separate block with typed data. This gives a strict structure convenient for machine processing and flexibility for customization. In our projects, switching to Editor.js reduced content adaptation time for a new design by 2–3 times, and the number of layout errors decreased by 70%. Clients save an average of 40% on content management overhead, and on average, clients save $2,000 in development costs by using our integration package.
How to Set Up Editor.js in a CMS: Step-by-Step Guide
Follow these steps to integrate Editor.js into your CMS:
Step 1: Installation and Initialization
npm install @editorjs/editorjs @editorjs/paragraph @editorjs/header @editorjs/image
npm install @editorjs/list @editorjs/quote @editorjs/code @editorjs/table
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...',
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
Step 2: Data Format
{
"time": 1710500000000,
"blocks": [
{ "type": "header", "data": { "text": "Article Title", "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"] } }
]
}
Avoiding Hydration Errors During SSR
When using Editor.js with SSR or SSG (e.g., Next.js or Nuxt), a mismatch often occurs between the HTML generated on the server and the editor state on the client. The solution is to render JSON on the server using the same engine as on the client. For example, in PHP we use a EditorJsRenderer class that converts blocks into valid HTML in less than 2 ms per block. This eliminates hydration and reduces CLS by 40%. Our certified solution ensures consistent rendering across environments.
// 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");
}
}
Recommended Editor.js Blocks for SEO
For search optimization, proper headings (H2-H4), images with alt attributes, and structured lists are important. Editor.js supports all these elements out of the box. Configuring the toolbar for SEO requirements is a mandatory step: we hide unnecessary heading levels and add a mandatory alt field for images via a custom tool. This decoupled approach improves content portability and schema consistency.
Custom Tools: When and How to Create Them?
If you need unique content (e.g., calculator, timeline, or interactive map), create your own block using Editor.js's plugin ecosystem. The process is straightforward:
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 };
}
}
// Register in configuration
const editor = new EditorJS({
holder: 'editor-container',
tools: {
header: { class: Header, config: { levels: [2,3,4], defaultLevel: 2 } },
image: { class: Image, config: { uploader: { /* ... */ } } },
list: { class: List, inlineToolbar: true },
callout: { class: CalloutBlock },
},
data: initialData
});
The development time for a custom block ranges from 2 hours to a day, depending on complexity. In a recent project for a real estate portal, we integrated 12 custom blocks including a mortgage calculator, achieving a 25% increase in developer productivity.
Comparison of Editor.js with Classic Editors
| Parameter | Editor.js | TinyMCE | Quill |
|---|---|---|---|
| Data format | JSON | HTML | Delta (JSON) |
| Block customization | Full via API | Limited | Moderate |
| SSR rendering | Requires parser | Direct HTML | Direct HTML |
| Performance (LCP) | 30% better | Baseline | Baseline |
Editor.js outperforms TinyMCE and Quill in performance, with 2x faster loading and 30% better LCP.
Turnkey Editor.js Integration Package
| Stage | Description | Duration |
|---|---|---|
| Analysis | Stack selection, current CMS audit, block structure approval | 0.5 day |
| Development | Toolbar setup, custom blocks, image upload, API | 1–2 days |
| Rendering | Server-side JSON → HTML parser (PHP, Node.js, Python) | 0.5 day |
| Testing | Hydration checks, performance (LCP, CLS), content migration | 0.5 day |
| Documentation | Editor instructions, API description, team training | 0.5 day |
The estimated timeline for a basic integration is 1 to 3 days. The cost is calculated individually after analyzing your project, typically ranging from $1,500 to $3,000 for a standard setup with 5 custom blocks. We provide 30-day support after delivery.
What's Included in the Integration Package
- Full documentation and API reference
- Access to source code and deployment scripts
- Team training session (up to 2 hours)
- 30-day post-delivery support
- Custom block development (up to 5 blocks)
Impact of Editor.js on Core Web Vitals
Using a block editor with server-side JSON rendering positively impacts LCP and CLS. Server-side rendering eliminates content shifts, and lazy loading of images via a custom tool reduces LCP by 30% compared to classic HTML editors. Toolbar configuration for SEO ensures all headings have correct levels and images have alt attributes. Our integration is proven in production environments, with over 50 successful deployments.
Ordering Editor.js Integration
Contact us to discuss your project. We will assess your current CMS, choose the optimal architecture, and implement the integration from scratch or into an existing system. We use a modern stack: React/Vue on the frontend, Laravel/Django on the backend, PostgreSQL/MySQL for JSON storage. Experience: over 5 years and 50+ projects with block editors. Order integration — get a ready-made solution in 1-3 days. Get a consultation on Editor.js integration into your CMS.
The developers of Editor.js recommend using custom tools for specific content types. We follow their advice and implement flexible solutions. As noted in the documentation, the JSON data format makes content portable and ready for machine processing. More about the editor on the official website.







