froala/nova-froala-field
Froala Nova Field integrates the Froala WYSIWYG editor into Laravel Nova, giving your resources a powerful rich text field with image and file uploads, configurable toolbars, and custom editor options. Easily add, edit, and manage formatted content directly within your Nova admin.
Architecture fit. This package is a single-purpose Nova Field subclass: a PHP class in vendor/froala/nova-froala-field/src/ that serializes an options array to JSON and hands it to a compiled Vue 2 component, which mounts the bundled Froala editor. There is no service provider, no publishable config, no migration, no scheduled job — nothing that touches application architecture. That is the good news: the integration footprint is one class and one dist/ asset bundle, and the persistence contract is plain HTML in a longText column. That last property is the strategically important one. It means the editor is a UI choice, not a data model, and swapping it later is a rewrite of a field class rather than a content migration. A TPM should treat "plain HTML in a column" as the single architectural guarantee worth defending in review, because it is what makes every exit ramp cheap.
Integration feasibility. High for the target window, near-zero outside it. The field targets Nova 3.x / Laravel 7–8 / PHP 7.4–8.0 / Vue 2. Nova 4 moved to Vue 3 and reworked field asset registration; a 2021 Vue 2 component will not mount, and there is no maintained fork to inherit. So feasibility collapses to a single gating question — what Nova version is in composer.lock — answerable in ten minutes and worth answering before any estimation. Assume positive feasibility, the work is genuinely one afternoon: register the field, define a longText column, configure a toolbar, prove the round trip (save, reload, inspect raw column = HTML not JSON), and build one upload endpoint. The non-trivial work is not integration, it is the surrounding obligations: a Froala license procurement and a sanitization layer. Both are prerequisites, not enhancements.
Technical risk. Concentrated and asymmetric — the wrapper is stable because it is frozen; the risk sits in the editor bundle and the licensing model.
key (v3) or licenseKey (v4), and the wrong one fails silently. A paid Froala plan buys editor support, not support for this Nova integration — there is no support contract for the field, ever.events, imageUploadParams, custom upload handlers) cannot survive JSON serialization at all — if the roadmap needs those, the cost is a Vue component fork, and that should be scoped as a distinct decision rather than discovered mid-sprint.Key questions. (1) What Nova version are we on, and is a Nova 4/5 upgrade funded or scheduled? If yes, this dependency is a dead end and the correct answer is "replace," not "adopt." (2) Is the authoring surface internal and low-exposure, or does this content flow to public-facing or compliance-sensitive pages? The latter converts a UI choice into an ongoing sanitization and CVE burden with no patch path. (3) Has licensing been approved — legal review, per-environment cost, renewal owner — before budget sign-off rather than after? (4) Do we need editor callbacks or custom upload behaviour? If so, add Vue component forking to the estimate. (5) What is our exit trigger, written down on day one?
Stack fit. Clean, provided we are inside the Nova 3 window. The field is a fluent Nova Field, so it drops into fields() alongside native fields with no routing, middleware, or service-provider changes. Everything is per-field ->options([...]). Two capabilities must be built by us and are not delivered by the package: the image/file upload endpoint (Froala POSTs the file and expects exactly { "link": "https://…" }; anything else — different key, wrapper envelope, 200-with-error-body — surfaces as "Something went wrong") and HTML purification.
Migration path. Two distinct migrations, and conflating them is the common planning error.
longText means content written today renders tomorrow under any editor. Enforce LONGTEXT from the start if base64 paste can't be prevented, and size-validate rules to the column (max:65535 for TEXT) so long articles don't truncate silently on MySQL non-strict or 500 on strict mode days after launch.App\Nova\Fields\RichText extends Froala, hold toolbars as named presets (->full(), ->minimal()) and all options in the constructor. When we replace the editor, one class changes and every resource follows. Optionally make the backend a config choice behind a feature flag with a plain Textarea fallback, so the revert is a toggle rather than a deploy.Compatibility. Pin everything — laravel/nova, the Froala package, PHP and Laravel minors — because no upstream compatibility work is happening. Compatibility with our own stack is the constraint we control; compatibility with future Nova is not on offer. Treat the package as a vendored, frozen dependency with a documented re-evaluation trigger.
Sequencing.
requestHeaders or an explicit exemption. Never let the editor accept a .svg with script inside.froala profile allowlisting exactly the enabled feature set, http/https only in URI.AllowedSchemes to block javascript:/data: links, and style stripped or tightly allowlisted.->hideFromIndex() on every rich-text field; add a readonly or truncated Text preview fallback so a broken editor never blocks the resource.Maintenance. Low frequency, non-zero effort, and entirely ours. There are no upstream patches to absorb — the package will not change. The maintenance burden is instead: monitoring Froala security advisories against a pinned bundle we cannot bump, keeping the sanitization allowlist aligned with the enabled toolbar, and re-evaluating at each Nova upgrade. Named owner required on the dependency register from installation day, with the trigger written down, because "archived" tends to become "invisible" after the launch sprint.
Support. Effectively none from any direction. The MIT wrapper has no commercial backing and the repo is archived; the Froala commercial plan supports the editor, not the Nova integration. Internal L1 triage is available and reasonably cheap if we write a runbook from the documented failure order: browser console for the Vue mount error (immediately tells you whether it's a Nova-version problem) → network tab for 404s on field assets after nova:publish or a Nova minor bump → hard refresh plus view:clear for Nova's cached asset manifest → confirm the field isn't swallowed by an authorization callback. Save failures with no error almost always mean the HTML never reached the request: check nullable and any silent max rejection. Escalation ceiling is "we fork the Vue component," which should be an explicit, budgeted decision rather than an incident-time improvisation.
Scaling. The wrapper scales fine — it's a form field. Two scaling concerns sit outside it. Content volume: base64 pasted images bypass the upload endpoint, bloat rows, and can breach MySQL TEXT's 65 KB ceiling; route paste through the uploader and use LONGTEXT. Blast radius: the risk profile scales with where content goes, not how much. An internal ops screen with fifty editors per day is fine indefinitely; the same field feeding public pages or anything compliance-sensitive is a liability that grows with traffic and with time-since-last-patch. Draw that boundary in the design, not in review.
Failure modes. (1) Silent option drop from a camelCase typo — blank toolbar, ~45-minute debug. (2) Vue mount failure after a Nova upgrade — field simply doesn't render. (3) Asset 404 after nova:publish or a Nova minor bump. (4) Upload rejection from a non-conforming JSON response shape, or CSRF 500 from missing requestHeaders. (5) Silent column truncation on long articles under MySQL non-strict. (6) XSS via unpurified HTML or a pasted hostile SVG, since the pinned editor bundle has known advisories. (7) Editor scrollbar-inside-scrollbar from using fixed height instead of heightMin — the most common unsolicited editor complaint. Every one of these is documented and cheap to pre-empt; none should be discovered in production.
Ramp-up. Very fast for anyone fluent in Nova — the mental model is one class: fluent options array → JSON → compiled Vue component. Budget half a day for a Nova-fluent engineer to the first verified round trip and one to two days to a hardened, sanitized, upload-enabled field. The dominant ramp-up cost is not the package, it is the two adjacent workstreams: licensing/procurement lead time and writing an allowlist that exactly matches the enabled toolbar. Do not let the field become load-bearing. Keep it flagged, keep the native field as an immediate fallback, keep content in plain HTML — and the moment content flows from it into public-facing or compliance-sensitive pages, the correct move is to replace the editor, not to harden the wrapper.
How can I help you explore Laravel packages today?