rahmanramsi/filament-editorjs
Editor.js integration for Filament forms. Adds a block-style rich text editor field to Filament resources and forms, letting Laravel admin panels create clean, structured JSON content with headings, lists, images, and more in a modern writing experience.
rahmanramsi/filament-editorjs provides an Editor.js block-editor field for Filament forms. Treat v2.0.0-beta.2 as a pre-release: pin the exact version and verify compatibility with your Filament major version before adopting it in production.
Minimal setup:
composer require rahmanramsi/filament-editorjs:2.0.0-beta.2
php artisan vendor:publish --tag=filament-editorjs-config
php artisan filament:assets
php artisan optimize:clear
Look first at:
composer.json for Filament/PHP version constraints.statePath behavior in nested forms.First use case: replace a plain textarea or rich-text field with block-based content in a Filament resource form.
use RahmanRamsi\FilamentEditorjs\Forms\Components\EditorJs;
EditorJs::make('content')
->label('Body')
->required();
Store Editor.js output as JSON:
// migration
$table->json('content')->nullable();
// model
protected $casts = [
'content' => 'array',
];
Basic resource form field
Use the package field directly in a Filament resource form. Keep the model attribute JSON-castable so Filament can hydrate and dehydrate the block document cleanly.
public static function form(Form $form): Form
{
return $form->schema([
EditorJs::make('content')
->label('Article body')
->columnSpanFull(),
]);
}
Store JSON, render server-side
Editor.js persists a document shape such as { "time": ..., "blocks": [...], "version": ... }. Do not assume it is HTML. Render blocks explicitly or use an Editor.js renderer on the frontend.
@foreach (($article->content['blocks'] ?? []) as $block)
@switch($block['type'])
@case('paragraph')
<p>{!! $block['data']['text'] ?? '' !!}</p>
@break
@case('header')
<h2>{!! $block['data']['text'] ?? '' !!}</h2>
@break
@endswitch
@endforeach
Sanitize any HTML-bearing block data before output.
Profiles and custom tools
Use package profiles/config to define which Editor.js tools are available per field. Keep separate profiles for simple article bodies versus richer pages with embeds, lists, or uploads. If you add custom Editor.js tools, register their JS assets and validate their stored block shapes server-side.
Nested forms, repeaters, and builders
The v2.0.0-beta.2 release restores statePath, which is the Filament mechanism that binds a field to the correct nested state path. If you use this field inside repeaters, builders, relation forms, or custom nested layouts, use beta.2 or newer rather than beta.1. Test hydration and dehydration explicitly in those layouts.
Actions and modals
The field can be used inside Filament action forms and modal forms, but verify asset loading and state binding there. Editor.js is a JS-heavy field; modal reopen cycles can expose stale-instance or missing-state issues.
Testing
In Livewire/Filament tests, assert the stored JSON structure rather than exact editor HTML. For nested forms, assert that the value lands under the expected state path after submit.
Livewire::test(ArticleResource\Pages\CreateArticle::class)
->fillForm([
'content' => [
'blocks' => [
['type' => 'paragraph', 'data' => ['text' => 'Hello']],
],
],
])
->call('create')
->assertHasNoFormErrors();
v2.0.0-beta.2 is pre-release software. Use 2.0.0-beta.2 exactly, or a stable v1 release if you do not need v2.statePath regression fixed. The only listed change in beta.2 is restoring statePath. If you tried beta.1 and saw values not binding correctly in nested forms, repeaters, or custom layouts, retest on beta.2.blocks and render each block type.text fields.null, plain HTML, or old JSON shapes. Normalize before passing data to the field or renderer.php artisan filament:assets and clear cached config/views. Missing Editor.js JS/CSS usually shows up as an empty editor shell.php artisan config:clear or php artisan optimize:clear; stale config is a common source of “my profile/tool change did nothing.”statePath.How can I help you explore Laravel packages today?