Власний WYSIWYG-редактор ми розробляємо, коли готові інструменти не справляються з унікальними вимогами: нестандартні блоки, строгий вихідний HTML, інтеграція з бекендом CMS. Наш досвід — 10+ років і 50+ проектів — дозволяє створювати редактори під ключ за 3–12 тижнів. Ми гарантуємо документацію, навчання та підтримку після здачі.
Готові редактори (TinyMCE, CKEditor) часто мають надлишкову функціональність або, навпаки, не дозволяють додати специфічні блоки: відео з кастомного плеєра, інтерактивні таблиці, вбудовування із зовнішніх сервісів. Крім того, вони генерують брудний HTML, який складно парсити на бекенді. Кастомний редактор дає повний контроль над моделлю даних і вихідним кодом.
Ми проектуємо редактор під конкретну CMS: Laravel, WordPress, Django або кастомне рішення. Контент зберігаємо в JSONB полях бази даних — це гнучко та індексується. На виході — швидкий, передбачуваний редактор з контекстним тулбаром, slash-командами та перетягуванням блоків.
Сценарії для кастомного WYSIWYG-редактора
Свій редактор пишуть, коли жодне готове рішення не закриває всі вимоги. Типові сценарії:
- Нестандартні блоки: кастомні галереї, інтерактивні схеми, вбудовування сторонніх сервісів через iframe.
- Чистий HTML: потрібен строгий вихідний код без зайвих обгорток, наприклад, для подальшої конвертації в PDF або e-mail.
- Глибока інтеграція: редактор повинен зберігати дані безпосередньо в CMS, працювати з медіатекою, підтримувати права доступу.
- Продуктивність: при сотнях блоків на сторінці готові редактори гальмують — потрібна віртуалізація та ліниве завантаження.
Який двигун вибрати: ProseMirror, Slate чи Lexical?
Писати редактор на голому contenteditable — шлях до нескінченних багів. Вибір стоїть між трьома зрілими двигунами:
| Двигун | Гнучкість | Продуктивність | Підтримка React | Складність освоєння |
|---|---|---|---|---|
| ProseMirror | Висока | Висока | Через Tiptap | Висока |
| Slate.js | Середня | Середня | Нативна | Середня |
| Lexical | Висока | Дуже висока | Нативна | Середня |
ProseMirror дає максимальний контроль над моделлю даних — його використовують, наприклад, у New York Times. Slate.js кращий для React-проектів, де важлива швидкість розробки. Lexical від Meta — найпродуктивніший, але спільнота ще невелика.
Як побудувати модель даних для редактора?
Редактор повинен працювати з чіткою схемою. Два популярних підходи: Flat JSON (список блоків) та Дерево (вкладена структура).
Приклад Flat JSON (стиль Editor.js):
{
"blocks": [
{ "id": "abc123", "type": "header", "data": { "text": "Заголовок", "level": 2 } },
{ "id": "def456", "type": "paragraph", "data": { "text": "Текст параграфа" } },
{ "id": "ghi789", "type": "image", "data": { "url": "/uploads/photo.jpg", "caption": "Підпис" } }
],
"version": "2.28.0"
}
Приклад дерева (ProseMirror/Tiptap):
{
"type": "doc",
"content": [
{
"type": "heading",
"attrs": { "level": 2 },
"content": [{ "type": "text", "text": "Заголовок" }]
},
{
"type": "paragraph",
"content": [
{ "type": "text", "text": "Звичайний " },
{ "type": "text", "marks": [{ "type": "bold" }], "text": "жирний" },
{ "type": "text", "text": " текст" }
]
}
]
}
У PostgreSQL дані зберігаються в jsonb з GIN-індексом для повнотекстового пошуку. Кожен тип блоку — окрема React-компонента з режимами перегляду та редагування. Реєструємо блоки через плагінну систему:
interface BlockPlugin<T = Record<string, unknown>> {
type: string;
label: string;
icon: React.ReactNode;
defaultData: T;
render: (data: T, ctx: RenderContext) => React.ReactNode;
edit: (data: T, onChange: (data: T) => void) => React.ReactNode;
validate?: (data: T) => ValidationError[];
toHTML?: (data: T) => string;
}
Контекстний тулбар, slash-команди та drag-and-drop
Тулбар з'являється лише при виділенні тексту — не займає місце і не відволікає. Реалізуємо плаваючу панель через FloatingToolbar з кнопками жирності, курсиву, посилання.
Slash-команди — стандарт для блочних редакторів: введення / відкриває меню вибору блоку. Фільтрація за назвою прискорює роботу.
Drag-and-drop сортування блоків реалізоване через @dnd-kit/core. Блоки перетягуються без втрати контенту.
Як працює історія змін?
class EditorHistory {
private undoStack: EditorState[] = [];
private redoStack: EditorState[] = [];
private maxSize = 100;
push(state: EditorState) {
this.undoStack.push(structuredClone(state));
if (this.undoStack.length > this.maxSize) this.undoStack.shift();
this.redoStack = [];
}
undo(current: EditorState): EditorState | null {
if (this.undoStack.length === 0) return null;
this.redoStack.push(structuredClone(current));
return this.undoStack.pop()!;
}
redo(current: EditorState): EditorState | null {
if (this.redoStack.length === 0) return null;
this.undoStack.push(structuredClone(current));
return this.redoStack.pop()!;
}
}
Для великих документів використовуємо імутабельні структури (Immer) для економії пам'яті.
Автозбереження — через дебаунс 2 секунди після останньої зміни. Статус відображається в інтерфейсі: «Збережено», «Збереження...», «Є зміни».
Рендеринг на фронтенді сайту
JSON редактора рендериться на публічній частині сайту. Два підходи:
- SSR через React — дані передаються в ті ж компоненти блоків, що й у редакторі. Ідеально для Next.js.
- Серверний рендеринг — на PHP або Node.js парсимо JSON і генеруємо HTML безпосередньо, без React.
| Підхід | Продуктивність | Складність | Гнучкість |
|---|---|---|---|
| SSR з React | Середня | Середня | Висока |
| Серверний рендеринг | Висока | Висока | Середня |
Приклад рендерера на Laravel:
class BlockRenderer
{
protected array $renderers = [];
public function register(string $type, callable $renderer): void
{
$this->renderers[$type] = $renderer;
}
public function render(array $blocks): string
{
return collect($blocks)
->map(fn($block) => ($this->renderers[$block['type']] ?? fn() => '')($block['data']))
->implode("\n");
}
}
Робота з медіа та продуктивність
Редактор інтегрується з медіатекою CMS. Зображення завантажуються через drag-and-drop прямо в блок — прогрес-бар показує статус. Для великих документів (сотні блоків і десятки зображень) вмикаємо віртуалізацію: рендеримо лише видимі блоки плюс буфер, інші замінюємо плейсхолдерами. Використовуємо react-window або @tanstack/virtual.
Що входить в роботу
- Аналіз вимог і проектування моделі даних
- Розробка ядра редактора та системи плагінів
- Реалізація типових і кастомних блоків
- Інтеграція з CMS через REST API або пряму роботу з БД
- Налаштування автозбереження, історії, медіатеки
- Тестування та налагодження
- Створення документації та навчання редакторів
- Гарантійна підтримка 12 місяців
Терміни та вартість
Орієнтовні терміни:
- MVP: 3–4 тижні
- Повноцінний редактор: 8–12 тижнів
- Складні проекти з унікальними блоками: до 16 тижнів
Вартість розраховується індивідуально залежно від складності. Конкретну цифру називаємо після аудиту вимог.
Чому обирають нас?
- 10+ років досвіду в розробці редакторів для медіа та корпоративних сайтів
- 50+ проектів — від невеликих блогів до великих порталів
- Прозорий процес: кожні 2 тижні демонструємо проміжні результати
- Гарантія 12 місяців і безкоштовна підтримка після запуску
Замовте розробку редактора під ключ — зв'яжіться з нами для консультації та отримайте інструмент, який повністю відповідає бізнес-завданням.







