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

Ux Quill Laravel Package

makraz/ux-quill

makraz/ux-quill is a Laravel package that adds a ready-to-use Quill rich-text editor Blade component. Drop it into forms, customize the toolbar, and store HTML or Delta content with minimal setup—ideal for clean WYSIWYG editing in Laravel apps.

View on GitHub
Deep Wiki
Context7

Getting Started

Read this first: despite the name, ux-quill is a Symfony UX bundle, not a Laravel package. There is no composer require path that "just works" in a Laravel app — the form type, Twig rendering, and Stimulus wiring assume Symfony's Form component, Twig, and symfony/stimulus-bundle. For a Laravel developer, treat this as a reference implementation or a package to port, not a drop-in dependency.

Minimal path if you're evaluating it:

  1. composer require makraz/ux-quill in a Symfony 6.4/7.x/8.x app (PHP ≥ 8.1).
  2. Ensure symfony/stimulus-bundle ≥ 2.9.1 is installed and your asset pipeline (AssetMapper or Webpack Encore) is running.
  3. Load Quill ≥ 2.0.0 — the bundle expects it available to the Stimulus controller.
  4. Register the form type and drop it into a form:
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;

class ArticleType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('title')
            ->add('body', QuillType::class, [
                'theme' => 'snow',
                'placeholder' => 'Write something…',
                'minHeight' => '20rem',
            ]);
    }
}
  1. Render the form in Twig as usual — no extra JS. The editor binds to a hidden input, syncs HTML on change, and fires native input/change events so Symfony validation and Live Components behave.

First use case: a single rich-text field on a create/edit form. That's the well-trodden path — don't try to retrofit it into a complex custom-field setup on day one.

EasyAdmin shortcut: if you're using EasyAdmin, QuillAdminField is a one-liner config; check that first before hand-rolling a form type.

Implementation Patterns

Basic form field. QuillType behaves like any other Symfony field — constraints, required, empty_data, and validation all work because the underlying value is a plain hidden input containing HTML. Persist it like any string column.

Two themes, pick per-field. theme => 'snow' for a classic toolbar (default) and theme => 'bubble' for a floating tooltip toolbar. Useful when you have a sidebar-heavy layout where a top toolbar eats vertical space.

Toolbar customization has three modes worth knowing:

  • Omit it → the default full toolbar (H1–H3, bold/italic/underline/strike, lists, blockquote, code block, link, image, clean).
  • Pass a Quill-compatible array → fine-grained control.
  • Pass '#my-toolbar' (CSS selector) → render your own toolbar markup in Twig and let Quill bind to it.
  • Pass false → no toolbar at all (pairs well with readOnly => true for preview screens).

Read-only / preview mode. Set readOnly => true and render the same form type in a "view" context. Cleaner than duplicating a Twig sanitizer path.

Event-driven extensions. The Stimulus controller exposes three DOM events — this is where most real customization lives:

document.addEventListener('quill:options', (e) => {
    // mutate e.detail.options before Quill boots
});

document.addEventListener('quill:connect', (e) => {
    // Quill is live; grab e.detail.quill if needed
});

document.addEventListener('quill:change', (e) => {
    const { html } = e.detail;
    // live word count, autosave draft, preview pane, etc.
});

Live Components integration. The bundle already handles data-live-ignore so the editor doesn't get clobbered on re-render. If you're writing a custom Stimulus controller around a Live Component, mimic that attribute.

Asset pipeline. Works with both AssetMapper and Webpack Encore. With Encore, confirm Quill is actually bundled — a missing Quill import is the most common "nothing renders" cause.

Porting to Laravel. If you want Quill-in-Laravel specifically, you're better off taking the ideas here (hidden input + two-way sync + the three event names) and wiring them to your own Blade component + Alpine or a small Stimulus controller via @hotwired/stimulus. The bundle's value to a Laravel dev is mostly as a clean spec.

Gotchas and Tips

It's Symfony, not Laravel. No service provider, no config/quill.php, no Blade directives. Any Laravel integration requires a port. Be honest with your team about that before composer require-ing anything.

Experimental = unstable. The release notes explicitly say backwards compatibility is not guaranteed between releases. Pin the exact version ("makraz/ux-quill": "0.1.0") and treat upgrades as mini-migrations. Do not put this on a client project's critical path yet.

HTML is stored raw. The bundle stores whatever Quill produces into a hidden field — no server-side sanitization is mentioned. Always sanitize on persistence or render (e.g. HTMLPurifier on the Symfony side; mews/purifier / HTMLPurifier on the Laravel side if you port). This is the single highest-risk item in the release.

minHeight type quirk. It accepts an int (pixels) or a CSS string ('20rem'). Passing a bare numeric string like '400' will produce invalid CSS — pass 400 (int) or '400px'.

Hidden input + validation ordering. The controller fires native input/change events specifically for form validation compatibility, but if you add your own JS validator, hook quill:change rather than polling the hidden field — the sync is async relative to keystrokes.

Live Component re-renders. data-live-ignore is set automatically on the field, but if you nest the editor inside a component that swaps DOM on every model update, you can still lose editor state. Wrap the editor in a data-live-ignore container yourself as belt-and-braces.

quill:options fires once per initialization. Mutating config after quill:connect has no effect — use the options event if you need to inject custom formats, modules, or bounds.

Bubble theme + toolbar config don't mix well. The bubble theme ignores a top toolbar; passing a custom toolbar selector with theme => 'bubble' produces confusing results. Choose one styling strategy.

EasyAdmin users: QuillAdminField is the fast path, but check the field's supported options against QuillType — the config surface may lag behind the form type. Fall back to QuillType in a custom CRUD form if you need an option the admin field doesn't expose.

Debugging checklist when the editor doesn't appear:

  1. Quill ≥ 2.0.0 actually loaded on the page (network tab).
  2. stimulus-bundle ≥ 2.9.1 and controllers are registered.
  3. The bundle's assets are published/imported per your pipeline (AssetMapper vs Encore).
  4. No JS error before the controller connects — check the quill:connect listener fires.

Where to extend: the three events are the intended extension points. Avoid reaching into the hidden input directly; the controller owns that node and will overwrite it on the next change.

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.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle