phil / block-editor-bundle
A block editor for Symfony forms, written in Stimulus controllers without a build step: slash menu, drag handles, inline toolbar, clean paste, nested blocks and columns, mentions and page links, image uploads, a reduced mode, reading and writing UJO (Universal JSON Output) documents checked by phil/
Package info
github.com/parler-haut-interagir-librement/block-editor-bundle
Language:JavaScript
Type:symfony-bundle
pkg:composer/phil/block-editor-bundle
Requires
- php: >=8.5
- ext-mbstring: *
- phil/ujo: ^0.1@dev
- phil/ujo-bundle: ^0.1@dev
- symfony/config: ^8.2
- symfony/dependency-injection: ^8.2
- symfony/form: ^8.2
- symfony/http-foundation: ^8.2
- symfony/options-resolver: ^8.2
- symfony/security-core: ^8.2
- symfony/security-csrf: ^8.2
Requires (Dev)
- phpunit/phpunit: ^13.4
- psr/log: ^3.0
- symfony/asset-mapper: ^8.2
- symfony/browser-kit: ^8.2
- symfony/event-dispatcher: ^8.2
- symfony/framework-bundle: ^8.2
- symfony/http-kernel: ^8.2
- symfony/routing: ^8.2
- symfony/security-bundle: ^8.2
- symfony/stimulus-bundle: ^3.7
- symfony/translation: ^8.2
- symfony/twig-bridge: ^8.2
- symfony/twig-bundle: ^8.2
- symfony/validator: ^8.2
- twig/twig: ^3.21
Suggests
- symfony/asset-mapper: To serve the controller and its stylesheet without a build step
- symfony/routing: For the image upload and reference search endpoints, and their URLs given to the editor
- symfony/stimulus-bundle: For the editor controller
- symfony/twig-bundle: For the form theme
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-11-11 13:29:34 UTC
README
A block editor for Symfony forms, in Stimulus controllers, that writes UJO (Universal JSON Output) documents checked on the server.
phil/block-editor-bundle gives a Symfony form a block editor in the manner of Notion. Writers add blocks from a slash
menu or a + button, turn one into another, move them by a handle or the keyboard, and nest them in toggles and
columns. They format text from a toolbar or with shortcuts, mention people with @, link pages with [[, upload
images, and paste from Word, Google Docs or any page without dragging its styles along. The editor reads and writes
UJO, the block document format of phil/ujo, into a hidden input. On submission phil/ujo checks that JSON and narrows
it to the field's tools. A reduced mode offers only paragraphs, headings, lists, quotes and links, for simple sites.
The bundle does not store documents or render them for readers; with phil/edit-lock-bundle, writers edit a document
together, one writer per block.
It is for any Symfony application whose writers compose pages, articles, wiki entries or forum posts as blocks. The
field is a form type like any other, so a document lands in an entity property as canonical JSON or as a Document.
For readers, phil/ujo-bundle renders it with ujo_html. The searches behind @ and [[, and the storage of
uploaded images, are the application's own: the bundle defines the ports and the routes, and the application writes a
class for each.
It is a Symfony bundle on phil/ujo and phil/ujo-bundle. The editor is a Stimulus controller served by AssetMapper,
with no build step, no npm package to install and no framework beyond Stimulus. Notion is the model of the interaction.
Its inline sanitizer in the browser mirrors the one of phil/ujo, so what is pasted is cleaned by the same rules the
server applies.
Status
| Part | State |
|---|---|
Toolset: block and inline tools, full and reduced presets |
Implemented and tested |
BlockEditorType, BlockEditorTransformer, the form theme: JSON checked and narrowed by phil/ujo |
Implemented and tested |
ToolsetNormalizers: one phil/ujo normalizer per toolset |
Implemented and tested |
ImageUploader, ReferenceSearch ports; ImageUploadController, ReferenceSearchController, routes |
Implemented and tested |
DocumentReferences: the mentions, page links and files of a document |
Implemented and tested |
| The editor controller: blocks, slash menu, handles, block menu, toolbar, shortcuts, paste, nesting, mentions, images, read-only mode, English and French | Implemented; pure modules tested under Node, the controller checked in a browser (testing) |
Writing together: the focus event, and the apply, remove and lock events another controller dispatches |
Implemented; place() tested under Node, checked in a browser with phil/edit-lock-bundle |
Documentation
| Document | What it covers |
|---|---|
| Installation | Requirements, enabling the bundle, the routes, the controller and the stylesheet. |
| Configuration | Every option, the services, and the toolsets. |
| Forms | BlockEditorType, its options, the form theme, and how a submitted document is checked. |
| The editor | The blocks, the menus, the handles, the toolbar, the shortcuts, pasting, nesting, read-only mode. |
| Integrations | Image uploads, the @ and [[ searches, a media library, usage tracking. |
| JavaScript | The controller's configuration, its events, its modules, its labels and its stylesheet. |
| Exceptions | The bundle's exceptions, and the answers of its endpoints. |
| Extension points | What an application implements, configures, replaces or relies on. |
| Testing | The PHP and Node tests, the mutation bar, and the checks made in a browser. |
| Reference | Every class and module of the bundle, with its role. |
Quick start
composer require phil/block-editor-bundle
use Phil\BlockEditorBundle\Infrastructure\Form\BlockEditorType; $builder->add('body', BlockEditorType::class); // the configured toolset $builder->add('summary', BlockEditorType::class, ['preset' => 'reduced']);
{{ form_row(form.body) }} {# the editor, through the bundle's form theme #}
{{ article.body|ujo_html }} {# for readers, with phil/ujo-bundle #}
Requirements
PHP 8.5 or later, Symfony 8.2, phil/ujo and phil/ujo-bundle. In the browser, Stimulus 3, served by
symfony/stimulus-bundle and AssetMapper.
Contributing
Contributions are welcome on the PHIL monorepo: read the contribution guide and the code of conduct. Report a vulnerability privately, as the security policy explains, never in a public issue.
License
MIT, © Philippe Gamache, doing business as Le Gnome Archiviste; a Parler Haut Interagir Librement project. See LICENSE.