darylseven/editorjs-bundle
Symfony bundle integrating Editor.js with Symfony Forms and Twig. Adds an EditorjsType form field, configurable editor setups, and a Twig helper to render/init the editor. Includes example config and JS init (Encore/webpack).
Install the Bundle
composer require tbmatuka/editorjs-bundle
Ensure Tbmatuka\EditorjsBundle\TbmatukaEditorjsBundle::class is added to config/bundles.php.
Configure the Bundle
Copy examples/editorjs.yaml to config/packages/editorjs.yaml and adjust settings (e.g., default tools, CDN paths).
Set Up Twig
Add the form theme to config/packages/twig.yaml:
twig:
form_themes:
- '@TbmatukaEditorjs/Form/editorjs_widget.html.twig'
Install Editor.js via npm (Encore)
npm install @editorjs/editorjs @editorjs/header @editorjs/paragraph
Copy examples/editorjs-init.js to your assets/js/ directory and import it in your Encore entry file.
Use in a Symfony Form
use Tbmatuka\EditorjsBundle\Form\Type\EditorjsType;
$builder->add('content', EditorjsType::class, [
'config' => ['tools' => ['header', 'paragraph']],
]);
Render the Form
{{ form_start(form) }}
{{ form_row(form.content) }}
<button type="submit">Save</button>
{{ form_end(form) }}
Replace a textarea in a blog post form with EditorjsType to enable rich-text editing. The bundle handles JSON serialization/deserialization automatically, so submitted data is stored as an array in your database.
EditorjsType in Symfony forms for structured rich-text input.$builder->add('description', EditorjsType::class, [
'config' => [
'tools' => [
'header' => HeaderTool,
'paragraph' => ParagraphTool,
'list' => ListTool,
],
'placeholder' => 'Enter content here...',
],
]);
$tools = ['header', 'paragraph', 'image']; // Image tool requires custom upload handler
$builder->add('content', EditorjsType::class, ['config' => ['tools' => $tools]]);
editorjs.yaml and reference them in Twig:
# config/packages/editorjs.yaml
editorjs:
configs:
blog_post:
tools: ['header', 'paragraph', 'embed']
placeholder: 'Write your blog post...'
{{ form_row(form.content, {'config': 'blog_post'}) }}
// Entity
#[ORM\Column(type: 'json')]
private array $content = [];
// Form handler
$entity->setContent($form->get('content')->getData());
// assets/js/editor-init.js
import EditorJS from '@editorjs/editorjs';
import Header from '@editorjs/header';
import Paragraph from '@editorjs/paragraph';
export default (selector, config) => {
const editor = new EditorJS({
...config,
tools: {
header: Header,
paragraph: Paragraph,
},
});
editor.render().then(() => {
document.querySelector(selector).appendChild(editor.rendered);
});
return editor;
};
webpack.config.js:
Encore
.addEntry('editorjs', './assets/js/editor-init.js')
.enableSingleRuntimeChunk();
AlertTool) and register it:
// assets/js/tools/AlertTool.js
export default class AlertTool {
static get toolbox() { return 'alert'; }
// ... implementation
}
# config/packages/editorjs.yaml
editorjs:
configs:
custom_tools:
tools: ['header', 'paragraph', 'alert']
twig.form_themes.// assets/js/editor-init.js
const loadPlugin = (name) => import(`@editorjs/${name}`).then(module => module.default);
use Symfony\Component\Validator\Constraints as Assert;
#[Assert\Type(type: 'array')]
#[Assert\All({
new Assert\Type(type: 'array'),
new Assert\NotBlank(),
})]
private array $content;
EditorjsType in PHPUnit:
$formFactory = $this->createMock(FormFactoryInterface::class);
$form = $formFactory->createNamedBuilder('content', EditorjsType::class, null, [
'config' => ['tools' => ['header']],
]);
Encore Dependency
Symfony 8 Form System Changes
FormBuilder and Twig forms. Test the bundle with:
FormBuilder::add() syntax.JSON Data Handling
#[ORM\Column(type: 'json')]
private array $content;
Plugin Compatibility
@editorjs/image: Requires custom upload handlers.@editorjs/embed: May need additional configuration for security.npm install to ensure plugin versions match your Editor.js core version.Twig Template Overrides
editorjs_widget.html.twig) may not fit your theme. Override it in:
templates/bundles/TbmatukaEditorjs/Form/editorjs_widget.html.twig
CSRF and Validation
$validator = $this->container->get('validator');
$errors = $validator->validate($form->getData());
Browser Support
Check Console for JS Errors
F12) to debug Editor.js initialization:
console.log('EditorJS initialized:', editor);
Uncaught TypeError: editorjs__WEBPACK_IMPORTED_MODULE_0___default.a is not a constructor: Missing or incorrect plugin imports.Failed to load resource: CDN or asset path issues.Validate Config
config/packages/editorjs.yaml is correctly formatted:
editorjs:
configs:
default:
tools
How can I help you explore Laravel packages today?