apimediaru/nova-tinymce
A Laravel Nova field that integrates the TinyMCE WYSIWYG editor into your admin panel, giving users a familiar rich-text editing experience with configurable toolbars and options for managing formatted content.
1. Install
composer require <vendor>/nova-editor
php artisan nova:publish # publish config + frontend assets
2. Publish the assets (2.0.4+)
Add the laravel-assets tag to your Nova layout / app.blade.php so the package's compiled JS and CSS are injected and auto-published for you instead of copying files by hand:
@laravelAssets
If you are on an older Nova version or a custom layout, keep the manual php artisan vendor:publish --tag=editor-assets step.
3. Look here first
config/nova-editor.php — tools, upload disk/path, sanitization toggles.vendor/<vendor>/nova-editor/resources/js — the Vue side, if you need custom tools or blocks.Editor) — this is what you reference in your Resource.4. First use case
Replace a plain textarea with the editor for a typical “Article body” field:
use Vendor\NovaEditor\Editor;
public function fields(NovaRequest $request)
{
return [
Text::make('Title')->rules('required', 'max:255'),
Editor::make('Body')
->rules('required')
->help('Rich text; stored as JSON.'),
];
}
Your body column should be json/longText holding the editor’s block document. Keep a rendered HTML copy (or render on demand) so your frontend never has to parse the block format.
Store blocks, render HTML separately. Treat the editor’s output as source-of-truth JSON and render it for the frontend:
// app/Models/Article.php
protected $casts = ['body' => 'array'];
public function bodyHtml(): string
{
return app(\Vendor\NovaEditor\Renderer::class)->render($this->body ?? []);
}
Cache the rendered HTML (body_html) on save if the field is read on high-traffic pages.
Reusable field presets. Define named configs (minimal, full, comment) and pass the profile from the Resource rather than repeating options:
Editor::make('body')->withProfile('full')->hideFromIndex(),
Editor::make('notes')->withProfile('minimal')->alwaysShow(),
Uploads / media. Point the package at a dedicated disk so image URLs, deletion, and pruning stay predictable:
// config/nova-editor.php
'uploads' => [
'disk' => env('EDITOR_DISK', 'public'),
'path' => 'editor/{user_id}/{date:Y}/{date:m}',
'max_size' => 5120,
],
Serve uploads through a controller if the disk is private, and mirror the same disk/path in any frontend renderer so relative URLs resolve.
Nested components (fixed in 2.0.4). Editors inside Nova’s nested resources, Panel, Tab, and relationship HasMany sub-forms now mount correctly. Pattern:
HasMany::make('Sections'),
// Section resource
Editor::make('body')->rules('required'),
When a parent form re-creates child rows, give each row a stable key (->resolveUsing(...)/unique attribute) so the editor keeps its content instead of reinitialising empty.
Custom tools/blocks. Register your JS tool against the editor instance and expose it via the package’s config; keep block renderers in one place so the Nova preview and the site output do not drift. Build with the package’s own toolchain, not your app’s Vite pipeline.
Validation & sanitization. Rules on the field only see the JSON blob, so add a custom rule that walks blocks (required, max blocks, allowed block types) and sanitize HTML server-side before persisting body_html.
Programmatic updates. When saving via API/imports, validate the document shape before assigning — a malformed array will render an empty editor and look like data loss.
composer update is almost always unpublished/browser-cached assets. Run php artisan nova:publish, php artisan view:clear, hard-refresh. On 2.0.4, verify @laravelAssets is present in your layout — without it the new auto-publishing path never runs and editors silently fail to boot.onMounted handlers that assume a single mount.index preview that shows a text extraction so you catch blank bodies.config/nova-editor.php changes need php artisan config:clear in local; in production the cached config wins over .env edits.disk or path later orphans existing images — migrate references, don’t just flip config.deleting hook or scheduled prune for the upload path, otherwise storage grows quietly.vendor/ files, which you will lose on the next release.laravel-assets publishing); drop the manual publish scripts from your deploy pipeline once @laravelAssets is wired in, and re-test any editor inside HasMany/Panel forms since the mount lifecycle changed.How can I help you explore Laravel packages today?