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

Quill Delta Parser Laravel Package

nadar/quill-delta-parser

A PHP library that parses Quill WYSIWYG editor Delta JSON into sanitized HTML. Every element is handled by the same flexible, extendable mechanism, making custom elements easy to add, output safer, and the parser simple to understand and customize. Install via Composer.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation / Upgrade

    composer require nadar/quill-delta-parser:^3.7.1
    

    If you are already on 3.7.0, upgrade to the security release:

    composer update nadar/quill-delta-parser
    

    3.7.1 fixes a stored XSS issue in URI schemes used by link, image, and video attributes. Upgrade if you render user-supplied deltas.

  2. Basic Usage

    use Nadar\QuillDeltaParser\Parser;
    
    $delta = [
        ['insert' => 'Hello '],
        [
            'insert' => 'World',
            'attributes' => [
                'bold' => true,
                'font' => ['size' => '24px'],
            ],
        ],
    ];
    
    $parser = new Parser();
    $html = $parser->parse($delta);
    // Output: <p>Hello <span style="font-size: 24px;"><strong>World</strong></span></p>
    
  3. First Use Case Parse raw Quill Delta JSON from an API or frontend into sanitized HTML for:

    • Storing parsed HTML in a database: $model->content_html = $html
    • Rendering in Blade templates: {!! $html !!}

    For user-generated content, treat 3.7.1 as the minimum safe version and still audit custom listeners/pre/post-processing that generate HTML.


Implementation Patterns

Core Workflows

  1. Frontend ↔ Backend Sync

    // Frontend: Quill.js
    const delta = quill.getContents();
    // Send delta JSON to Laravel via API
    
    // Backend: Laravel Controller
    $delta = json_decode(request('delta'), true);
    $html = (new Parser())->parse($delta);
    
  2. Database Storage

    Schema::create('posts', function (Blueprint $table) {
        $table->id();
        $table->text('content_html');
        $table->json('content_delta')->nullable();
    });
    

    Store the raw delta when you may need to re-render later, and store the rendered HTML for fast display.

  3. Blade Rendering

    <div class="quill-editor">
        {!! $post->content_html !!}
    </div>
    

Advanced Patterns

  1. URI Scheme Allowlist for Links / Images / Videos 3.7.1 validates URI schemes before writing href/src attributes. Unsafe schemes such as javascript: are neutralized: links become #, and unsafe images/videos are omitted.

    If you intentionally support custom schemes such as ftp, extend the corresponding listener:

    $link = new Link();
    $link->safeSchemes = ['http', 'https', 'mailto', 'tel', 'ftp'];
    
    $lexer->overwriteListener(new Link(), $link);
    

    Apply the same idea to image/video listeners if you need custom media schemes. Keep this list narrow.

  2. Font Size Customization

    $parser = new Parser();
    $parser->setFontSizeMap([
        'small' => '12px',
        'medium' => '16px',
        'large' => '24px',
    ]);
    
  3. Custom Elements with Font Support

    $parser = new Parser();
    $parser->addCustomElement('mention', function ($attrs, $text) {
        $fontSize = $attrs['font']['size'] ?? '16px';
        return '<span class="mention" style="font-size: ' . $fontSize . '" data-id="' . $attrs['id'] . '">@' . $text . '</span>';
    });
    

    Escape any dynamic values inside custom element callbacks.

  4. Delta Validation

    use Nadar\QuillDeltaParser\Validator;
    
    $validator = new Validator();
    
    if ($validator->validate($delta)) {
        $html = (new Parser())->parse($delta);
    }
    

    Use Validator for delta shape, not as a full HTML sanitizer.

  5. Batch Processing

    $parser = new Parser();
    
    $deltas = collect($request->deltas);
    $htmls = $deltas->map(fn ($delta) => $parser->parse($delta));
    

Gotchas and Tips

Common Pitfalls

  1. Stored XSS / URI Schemes

    • 3.7.1 fixes stored XSS via link, image, and video URI attributes.
    • Unsafe javascript: links are neutralized to #; unsafe images/videos are not rendered.
    • This does not replace escaping text or auditing custom HTML generation.
    • If you use custom listeners, pre-processing, or post-processing to emit HTML, sanitize/escape those values yourself.
  2. Custom URI Schemes After Upgrade

    • If existing content relies on ftp:// or another non-default scheme, it may now be neutralized.
    • Add only the schemes you truly need to the listener’s $safeSchemes property:
      $link = new Link();
      $link->safeSchemes = ['http', 'https', 'mailto', 'tel', 'ftp'];
      $lexer->overwriteListener(new Link(), $link);
      
    • Do not add javascript, data, or other unsafe schemes.
  3. Nested Deltas

    • Quill’s nested structures, such as lists, require recursive parsing. The parser handles common cases, but custom elements may break nesting if they return unexpected block markup.
  4. Font Size Attribute Handling

    • font.size maps to inline style="font-size: ...".
    • Override mappings with setFontSizeMap() when your frontend uses semantic sizes like small, medium, large.

Debugging Tips

  1. Log Raw Deltas

    \Log::debug('Raw Delta:', $delta);
    

    Verify the Quill op structure, especially attributes:

    ['insert' => 'text', 'attributes' => ['bold' => true, 'font' => ['size' => '24px']]]
    
  2. Inspect HTML Output

    $html = $parser->parse($delta);
    \Log::debug('Generated HTML:', [$html]);
    

    Specifically inspect rendered href and src attributes after upgrading.

  3. Test Unsafe URI Payloads

    • Add a regression test with a javascript: link and confirm it renders as #.
    • Add a test for unsafe image/video attributes and confirm they are omitted.
    • If you allow ftp, add a test proving it still renders only where intended.
  4. Custom Element Quirks

    • Check attribute names carefully: font.size vs font-size.
    • Verify returned HTML structure for self-closing tags, block wrappers, and nested content.

Extension Points

  1. Override Default Tags

    $parser->setTagMap([
        'bold' => 'b',
        'italic' => 'i',
    ]);
    
  2. URI Scheme Allowlists

    $link = new Link();
    $link->safeSchemes = ['http', 'https', 'mailto', 'tel', 'ftp'];
    $lexer->overwriteListener(new Link(), $link);
    
  3. Font Size Customization

    $parser->setFontSizeMap([
        'small' => '12px',
        'medium' => '16px',
        'large' => '24px',
    ]);
    
  4. Pre/Post-Processing

    $parser->setPreProcess(function ($delta) {
        return $delta;
    });
    
    $parser->setPostProcess(function ($html) {
        return '<div class="content">' . $html . '</div>';
    });
    

    Be extra careful with post-processing: it can reintroduce unsafe HTML if it wraps or injects untrusted values.

  5. Performance

    • Reuse a Parser instance for bulk parsing:
      $parser = new Parser();
      
      foreach ($deltas as $delta) {
          $html = $parser->parse($delta);
      }
      
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.
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
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator