Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Nova Trumbowyg Laravel Package

alfonsobries/nova-trumbowyg

A Laravel Nova field that integrates the lightweight Trumbowyg WYSIWYG editor, giving your Nova admin resources a clean, customizable rich-text input for creating and editing HTML content.

View on GitHub
Deep Wiki
Context7

Getting Started

Requirements first: this field was last released in 2018 and the repo is archived. Check composer.json before installing — it targets Nova 1.x (and therefore Vue 2 + the older Nova asset pipeline). It is not a drop-in for Nova 2/3/4.

composer require alfonsobries/nova-trumbowyg

If the package ships published assets, run php artisan vendor:publish once; otherwise the compiled JS/CSS in dist/ is loaded by the field component itself.

First use case — replacing a Textarea on a Post/Blog resource:

use Alfonsobries\NovaTrumbowyg\NovaTrumbowyg;

public function fields(Request $request)
{
    return [
        ID::make()->sortable(),
        Text::make('Title')->rules('required', 'max:255'),

        NovaTrumbowyg::make('Body')
            ->rules('required')
            ->help('Rich text is stored as raw HTML.'),
    ];
}

The field resolves to an HTML string, so the column should be text/longText. Render it with {!! $post->body !!} (after sanitizing) — the editor is only the input mechanism.

Where to look first (in this order):

  1. src/NovaTrumbowyg.php — the field class and its options() / withOptions() API. Confirms the exact method names used below.
  2. resources/js/components/Field.vue — how Trumbowyg is mounted on the wrapper element, and where the initialization options are read from.
  3. resources/js/field.js / dist/js/* — how the jQuery/Trumbowyg assets are registered with Nova.
  4. Trumbowyg's own docs (alex-d.github.io/Trumbowyg) for the actual option names (btns, btnsDef, semantic, resetCss, lang, plugins).

Implementation Patterns

Configuring the toolbar — pass Trumbowyg options straight through (JSON-serialized into the component):

NovaTrumbowyg::make('Body')
    ->options([
        'lang'      => 'en',
        'resetCss'  => true,
        'btns'      => [
            ['viewHTML'],
            ['undo', 'redo'],
            ['formatting'],
            ['bold', 'italic', 'underline', 'strikethrough'],
            ['link'],
            ['justifyLeft', 'justifyCenter', 'justifyRight', 'justifyFull'],
            ['unorderedList', 'orderedList'],
            ['removeformat'],
        ],
        'semantic'  => ['div' => 'p'],
    ]);

Keep the toolbar small — Trumbowyg's differentiator is a lightweight editor, and a 30-button toolbar in a Nova form is worse than a Markdown textarea.

Splitting display from editing. The raw HTML string is a poor index/detail cell. Standard pattern:

NovaTrumbowyg::make('Body')->onlyOnForms(),

Text::make('Body', 'body')
    ->onlyOnIndex()
    ->displayUsing(fn ($value) => Str::limit(strip_tags($value), 80)),

Text::make('Body')
    ->onlyOnDetail()
    ->asHtml(), // or displayUsing() returning an HtmlString of sanitized HTML

Sanitization / normalization. Never trust the submitted HTML. Either sanitize in the Nova field's fill()/resolveUsing via an observer/mutator, or use a Spatie\Html-style sanitizer:

public function setBodyAttribute($value)
{
    $this->attributes['body'] = app(Sanitizer::class)->sanitize($value);
}

Same field, multiple times on one form. Trumbowyg attaches to a DOM node, not a global. Confirm the Vue component scopes its selector to its own $el; if you see two editors fighting over one instance, that's why. Give each field a distinct attribute and test side-by-side.

Searchable / sortable. The underlying column is text, so ->searchable() works on the raw text (HTML tags included in the query) — acceptable for most uses, misleading if you rely on it heavily. Consider a separate plain-text column populated in the mutator if search matters.

Reusing rendered output. Treat the resource field purely as input; render the stored HTML through a Blade partial (resources/views/posts/body.blade.php) so front-end typography styles live in your app, not in Nova.

Gotchas and Tips

  • Archived and unmaintained. No fixes for newer Nova. Before adopting, diff src/ against your installed Nova version — the Vue 2 component API and Nova::script() asset registration are the usual breakages. If you're on Nova 3+, look at actively maintained alternatives (nova-tiptap, CKEditor or TipTap-backed fields) or build a thin custom field around Trumbowyg yourself.
  • jQuery dependency. Trumbowyg requires jQuery. The package either bundles it or expects it globally. Bundling a second jQuery on a Nova page is a classic source of "silently broken buttons" — check what the component actually imports before debugging Trumbowyg itself.
  • Cleanup. Trumbowyg instances are not GC'd automatically. If the Vue component has no beforeDestroy, navigating between resources repeatedly leaks DOM listeners. Add trumbowyg.destroy() in a $destroy hook as an extension point.
  • Z-index and modals. The link-prompt / modal overlay often renders under Nova's modal or toolbar. A CSS override on .trumbowyg-modal z-index is the standard fix; scope it in your Nova CSS (Nova::style()) rather than editing dist/.
  • Option naming. Trumbowyg uses btns (array of button groups) and btnsDef (button definitions) — not a flat buttons list. Passing the wrong key fails silently: the editor renders with the default toolbar. Verify by inspecting the mounted component's props in Vue devtools.
  • Images / uploads. Trumbowyg has an image-upload plugin, but this wrapper does not wire up an endpoint for it. You cannot rely on a Nova File field to handle uploads — you'd need a custom route + plugins config, at which point a maintained editor is usually cheaper.
  • resetCss. With resetCss => true the editor strips browser heading/paragraph styling; without it, content pasted from Word looks wildly different between the editor and your front end. Test paste behavior early.
  • Language files are served from Trumbowyg's langs/; if lang is set but you see English, the asset path isn't published.
  • Validation. Trumbowyg can submit <p><br></p> for an "empty" editor. Use a nullable/required rule combined with a custom trim-style check (strip_tags($value) === '') if the field is mandatory.
  • Debugging. There's no meaningful error surface: if the toolbar doesn't appear, check (in order) that the wrapper element exists when trumbowyg() is called, that jQuery is loaded, and that Trumbowyg's CSS is present — a missing stylesheet makes the editor look like an unstyled textarea rather than throwing.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route