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 Quill Field Laravel Package

nevadskiy/nova-quill-field

A Laravel Nova field that integrates the Quill WYSIWYG editor into your admin panel, making it easy to add rich text content fields to Nova resources. Customize the toolbar, store content as HTML, and enjoy simple, flexible setup for forms and detail views.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit. The package is a single Laravel Nova custom field that wraps the Quill editor: a thin PHP field class (src/Quill.php) plus a Vue component under resources/js/components. There is no service provider to register, no migrations, no domain logic, and no public API beyond Quill::make() and withMeta(). Architecturally that is close to the ideal shape for a third-party dependency — the blast radius is one field on one Nova resource, and the data contract is simply "HTML in a text column." It is not a content platform, a sanitization layer, an asset/media pipeline, or a customer-facing editor strategy, and it should never be scoped as one. The correct framing for planning purposes: this is a UI convenience that shortens the critical path on an internal admin feature by roughly a few days to a week, purchased with a small, well-bounded dependency risk.

Integration feasibility. Low effort for a team already on Nova: Composer install (auto-discovered), one longText column, one field declaration, one Blade render. Because the entire public surface is two files, a spike can be credibly timeboxed at half a day to two days including QA — not a sprint. Two items drive real effort and belong in the plan, not in the "discovered later" column:

  • Sanitization is unfunded work in the package. Quill emits HTML; {!! $content !!} is an XSS vector. That means a purifier dependency, an allowlist matching Quill's tag set, a write-time mutation path (mutator or observer), and test coverage for it. Small, but genuine engineering — and it is a prerequisite, not a follow-up.
  • Draft/create is a distinct integration path from edit. The 0.1.2 fix ("use draftId for field attachments") confirms that attachments resolve differently inside Nova draft resources. Plan a separate test case for create-with-attachment (create → attach before saving → save → reload → confirm resolution) rather than assuming the edit-flow smoke test covers it.

Technical risk. High relative to value, and the 0.1.2 patch changes the character of that risk only marginally. Signals: 4 stars, 0 dependents, a single 0.x line, last release May 2023, and the latest release is a maintainer bug fix rather than evidence of an active roadmap.

  • Security. All XSS responsibility lands on us. Nova escapes by default; {!! !!} does not. Sanitizing only at render time leaves every other consumer — API, mail, RSS, Nova's own HTML detail view — exposed. Write-time sanitization is the only defensible posture, and it is our code, not the vendor's.
  • Commercial coupling. Nova is a paid product with an evolving asset pipeline and draft-resource lifecycle. Unmaintained third-party fields are historically the first casualties of a Nova major upgrade, and the package documents no supported Nova/PHP version matrix.
  • Data loss by design. Quill normalizes markup on round-trip: it strips class, most style, merges adjacent tags, and drops unsupported elements. Any imported legacy CMS content or Word paste visibly mutates the first time an editor opens and saves. This is product-visible behavior, not a bug, and it needs a policy decision before the field is enabled on existing content.
  • Media handling is a footgun. Quill's stock image button inserts base64 data URIs into the HTML. A handful of pasted screenshots becomes multi-megabyte rows, slow saves, and timing-out index pages. The image button must be replaced with an upload endpoint or disabled outright in the first pass.
  • Configuration is undocumented. There is no docs site; the source is the API. Options are passed through withMeta() and read by the Vue component, so meta-key mismatches fail silently ("the option doesn't work"). Custom buttons or Quill modules require Quill.register(...) in the Vue layer — there is no PHP-only path, so those are fork-scoped, not config-scoped.

Key questions to close before committing.

  1. Which specific Nova resources and which named fields are in scope for the pilot — and is the count capped?
  2. Is any rendered output reachable by unauthenticated users, directly or via API/mail/RSS? If yes, the risk tier changes and sanitization becomes a launch blocker with its own review.
  3. Do we use Nova draft resources today, and does the editorial workflow depend on them?
  4. Do authors need images or embeds in v1? If yes, who owns the upload endpoint — this is the largest hidden scope item.
  5. What Nova major version are we on, and what is the upgrade cadence over the next 12 months? That cadence is the re-validation cost.
  6. Does any target resource use spatie/nova-translatable or another field wrapper? Thin field packages are exactly where wrappers break; this must be verified, not assumed.
  7. Who owns the fork-or-swap fallback, and what is the trigger condition for invoking it?

Integration Approach

Stack fit. Laravel + Laravel Nova + Composer auto-discovery. The hard prerequisite is an existing Nova license and an established Nova resource-authoring practice; if the team is not already on Nova, this package is irrelevant and the conversation should stop. PHP/Laravel/Nova version support is undocumented, so the first spike task is establishing a tested matrix on our actual stack rather than trusting the README.

Migration path. Treat the field as greenfield-per-column wherever possible.

  • New content: add longText nullable, wire Quill::make(), render behind sanitization. Clean.
  • Existing HTML: the risky path. Round-tripping legacy markup through Quill will strip classes and styles and reflow structure. Either pre-convert imported content to Quill's supported tag set (p, br, strong, b, em, i, u, s, h1–h6, ol, ul, li, blockquote, a, img, pre, code) before enabling the field, or keep import-only content off this field entirely and expose it read-only.
  • Derived data: a content_text companion column (populated in the same observer via strip_tags + truncation) should ship with the first migration, not later. LIKE '%term%' against HTML matches tag names and attributes; search, excerpts, meta descriptions, and word-count rules all need the plain-text column, and retrofitting it means a backfill.
  • Version floor: pin ^0.1.2 at minimum. On 0.1.1, a Quill field inside a Nova draft resource can attach to the wrong form state — symptoms are content that won't persist or a second editor silently losing its value.

Compatibility. Three surfaces need explicit verification during the spike, each of which is currently undocumented: (a) Nova major version and asset pipeline — confirm the package's compiled dist assets are actually served, and whether nova:publish is required; (b) draft resources — re-test after every upgrade; (c) translation wrappers, if used. Record the results as our own tested matrix in the repo, because the upstream project will not maintain one for us.

Sequencing. Recommended four-phase path with explicit gates:

  1. Timeboxed spike (0.5–2 days). Install, mount the field on a throwaway resource, confirm the editor renders and saves, enumerate the actual withMeta() keys the Vue component reads, and capture the tested version matrix. Gate: editor mounts and round-trips on our Nova version.
  2. Pilot on one internal admin resource (≈3–5 days including surrounding work). Ship the field with its support structure: write-time sanitization + allowlist + tests, content_text derivation, excerpt column on index with the Quill field onlyOnForms()/hideFromIndex(), image button disabled or replaced, and ->rules(['required','string','max:65535']) as a rough guardrail. Gate: security review of the write path passes; no base64 rows in the pilot table.
  3. Harden and document. Add the create-with-attachment smoke test, the Nova-upgrade smoke-test checklist, and a one-page internal doc recording meta keys, tested versions, and the exit path. Gate: a second engineer can add a Quill field to a new resource from the doc alone.
  4. Expand only if gates pass. Additional resources are cheap if step 2's plumbing is reusable — which is why field presets should be a Quill subclass with the toolbar/placeholder baked in, rather than copy-pasted withMeta() chains across resources.

Cross-cutting workstreams that must be staffed regardless of phase: dependency pinning, sanitization, media policy, markup-normalization QA, and the Nova-upgrade smoke test.

Operational Impact

Maintenance. Sporadic and unpredictable. Pin the exact version in composer.json (not a floating ^ range) and treat every Nova major upgrade as a mandatory re-validation event — Nova's asset pipeline has broken third-party fields before, and there is no upstream commitment to fix it. The mitigating factor is genuinely favorable: the entire integration surface is two files, so forking the Vue component or the PHP field into the app is a bounded, well-understood task rather than a rewrite. Budget the fork as a plausible outcome, not a last resort, and note that preset subclasses in our own codebase reduce the amount of fork surface we'd inherit.

Support. No vendor, no SLA, no issue-response guarantee, no documentation beyond the README. Internal ownership is required from day one: a named engineer for the fork, a named owner for the sanitization allowlist (it will need to evolve), and a written record of tested versions. Escalation for "editor doesn't mount" is our own team reading src/Quill.php and the Vue component — which is tractable, but it is our time, not someone else's.

Scaling. The relevant axis is breadth of adoption, not traffic. Cost scales with number of resources, number of editors, and number of locales. Multi-locale means one Quill field per locale column — predictable, but it multiplies the sanitization and validation surface. The one place it scales badly on data volume is base64 images: row size grows with pasted screenshots, index pages slow down, saves slow down, and database backups quietly inflate. Keeping the field off index lists and forcing images through an upload endpoint are the two controls that make scaling a non-issue.

Failure modes and controls.

Failure mode Signal Control
Stored XSS via rendered HTML Security review finding; injected <script>/onerror survives a save Sanitize at write time with an allowlist; treat stored value as untrusted outside Blade
Base64 image bloat Multi-MB rows; slow saves; index timeouts Replace or disable the image handler in v1; add a size rule
Silent markup loss on edit Editors report formatting "disappearing" after opening/saving imported content Pre-convert imported HTML to Quill's tag set, or exclude import-only content from the field
Draft attachment misbehavior Content not persisting in draft resources; second editor appears to lose its value Require 0.1.2+; explicit create/attach/save/reload smoke test
Field fails to mount after Nova upgrade Blank or non-interactive editor Pin version; smoke-test on every upgrade; verify dist assets are served
Config silently ignored "I set the toolbar and nothing changed" Inspect the Vue component for the exact meta key; document keys we rely on
Detail view renders blank/read-only QA on the detail page Pair with Text::make('Content')->asHtml() on detail, hide the Quill field there
Custom button/module needed Requirement exceeds config surface Fork the Vue component and override component(); no PHP-only path exists

Ramp-up. A Nova-experienced developer reaches productive use in half a day; the documentation gap adds an hour of meta-key guessing if they skip the source. Reduce this to near-zero with two artifacts: a field-preset subclass (ArticleBody extends Quill) that encodes the toolbar and options once, and a one-page internal note listing the meta keys we use, the tested version matrix, and the exit path. QA ramp-up is the larger cost — reviewers need a normalization checklist (open, save, diff the stored HTML) because Quill's markup rewriting is invisible until someone compares before and after.

Bottom line for the plan. Fund the pilot, not a rollout. The value is a few days of avoided editor work on an internal admin surface; the cost is a pinned dependency plus roughly a day of plumbing (sanitization, plain-text companion, image policy) that the package does not provide. Commit to expansion only after the pilot's security review and upgrade smoke test pass — and document the fork-or-swap exit path while the integration is still one resource wide.

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.
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log