PHPackages                             digitonic/filament-rich-editor-tools - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. digitonic/filament-rich-editor-tools

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

digitonic/filament-rich-editor-tools
====================================

A package designed to improve the existing Filament Rich Editor

2.0.0(3mo ago)0826↓33.3%MITPHPPHP ^8.2|^8.3|^8.4|^8.5CI passing

Since Jan 13Pushed 2mo agoCompare

[ Source](https://github.com/digitonic/filament-rich-editor-tools)[ Packagist](https://packagist.org/packages/digitonic/filament-rich-editor-tools)[ Docs](https://github.com/digitonic/filament-rich-editor-tools)[ RSS](/packages/digitonic-filament-rich-editor-tools/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (7)Dependencies (11)Versions (9)Used By (0)

Filament Rich Editor Tools (Filament 4/5 Panels)
================================================

[](#filament-rich-editor-tools-filament-45-panels)

This package integrates deeply with Filament 4/5 Panels Rich Editor via macros and service provider hooks, effectively taking over and enhancing much of the core Rich Editor functionality to provide a more feature-rich experience.

Requirements
------------

[](#requirements)

- PHP 8.4+
- Laravel 12
- Filament 4/5 Panels Rich Editor
- Livewire v3

Installation
------------

[](#installation)

Install the package via Composer:

```
composer require digitonic/filament-rich-editor-tools
```

The service provider will be auto-discovered. No manual registration is needed.

Overview
--------

[](#overview)

This package extends Filament 4/5 Panels Rich Editor through a comprehensive integration that:

- **Automatically enhances all Rich Editor instances** with additional functionality via Laravel's service container
- **Provides a unified `RichEditorUtil` class** that ensures your editor and renderer configurations stay synchronized
- **Registers custom blocks globally** so they're available in any Rich Editor field
- **Adds macro methods** to `RichContentRenderer` for advanced content processing
- **Handles heading ID assignment** automatically for better SEO and navigation

The integration is designed to be seamless - simply replace your existing `RichEditor::make()` calls with `RichEditorUtil::make()` to access all enhanced features.

What it adds
------------

[](#what-it-adds)

This package enhances Filament's Rich Editor through automatic registration and macros:

1. **TipTap PHP extensions** automatically registered on every Filament Rich Editor renderer instance:

    - Heading ID support for automatic anchor generation
    - Enhanced table of contents generation capabilities
2. **Macros on Filament's `RichContentRenderer`** for advanced content processing:

    - `toTableOfContents(int $maxDepth = 3): array` — returns a nested TOC array from the current renderer content
    - `processHeaderIds(Editor $editor, int $maxDepth = 3): void` — assigns unique IDs to heading nodes inside a TipTap `Editor`
3. **Four production-ready custom blocks** (detailed below):

    - **Pros &amp; Cons Block**: Side-by-side comparison lists with icons
    - **Video Block**: Embeddable YouTube and Vimeo videos with captions
    - **Twitter Embed Block**: Native Twitter/X post embedding
    - **Table of Contents Block**: Dynamic, navigable content outline
4. **Migration command** for legacy content conversion:

    - `php artisan filament-rich-editor-tools:migrate-blocks` to convert old TipTap blocks to Rich Editor format
    - Automatically migrates `tiptapBlock` → `customBlock` node types
    - Converts `textStyle` marks to `textColor` marks for Filament 4 compatibility
    - Maps hex color values to Filament's named color system
5. **Unified Editor/Renderer utilities** that ensure consistency between editing and display modes

These features are registered globally and applied automatically to all Rich Editor instances in your application.

Usage
-----

[](#usage)

### Convert your blocks

[](#convert-your-blocks)

The migration command converts content from Filament 3's TiptapEditor format to Filament 4's RichEditor format:

```
php artisan filament-rich-editor-tools:migrate-blocks "App\Models\Page" blocks
```

Replace the model and field name as needed. This will overwrite existing DB records. So take a backup.

If you have a complex JSON structure with your rich editor located on something like `meta.content` you can use dot notation to specify the field.

```
php artisan filament-rich-editor-tools:migrate-blocks "App\Models\Page" meta.content
```

#### What the migration does

[](#what-the-migration-does)

**Block Migration:**

- Converts `tiptapBlock` node types to `customBlock`
- Renames `attrs.type` to `attrs.id`
- Renames `attrs.data` to `attrs.config`
- Normalizes block IDs (removes "Block" suffix, converts to lowercase)

**Color Migration (textStyle → textColor):**

When migrating from Filament 3, colored text stored with `textStyle` marks causes errors in Filament 4:

> "There is no mark type textStyle in this schema"

The migration automatically converts:

```
// Before (Filament 3):
{
  "type": "textStyle",
  "attrs": { "color": "#1E7F75" }
}

// After (Filament 4):
{
  "type": "textColor",
  "attrs": { "data-color": "green" }
}
```

The migration maps hex colors to Filament's named color system (red, orange, amber, yellow, lime, green, emerald, teal, cyan, sky, blue, indigo, violet, purple, fuchsia, pink, rose, gray).

#### Custom Color Mappings

[](#custom-color-mappings)

If you have custom hex colors that need specific mappings, add them to your config:

```
// config/filament-rich-editor-tools.php
return [
    'color_map' => [
        '#1E7F75' => 'green',
        '#custom123' => 'brand',
        // Add more custom mappings as needed
    ],
];
```

For hex colors not in the map, the migration finds the closest matching color using RGB distance calculation.

### Use our editor

[](#use-our-editor)

In your Filament form or page, to get our rich editor do the following:

```
RichEditorUtil::make('raw_content'),
```

### Use our Renderer

[](#use-our-renderer)

In your Filament form or page, to get our renderer do the following:

```
RichEditorUtil::render($content);
```

#### Render Types

[](#render-types)

The renderer supports multiple output formats via the `RenderType` enum:

```
use Digitonic\FilamentRichEditorTools\Enums\RenderType;
use Digitonic\FilamentRichEditorTools\Filament\Utilities\RichEditorUtil;

// Default HTML output (sanitized - safe for untrusted content)
$html = RichEditorUtil::render($content, RenderType::HTML);

// Unsafe HTML output (preserves iframes, scripts - use for trusted content only)
$html = RichEditorUtil::render($content, RenderType::UNSAFE_HTML);

// Plain text output
$text = RichEditorUtil::render($content, RenderType::TEXT);

// Array/JSON output
$array = RichEditorUtil::render($content, RenderType::ARRAY);

// Table of contents
$toc = RichEditorUtil::render($content, RenderType::TOC);

// Get the renderer instance for further customization
$renderer = RichEditorUtil::render($content, RenderType::RENDERER);
```

#### When to use UNSAFE\_HTML

[](#when-to-use-unsafe_html)

By default, `RenderType::HTML` sanitizes the output and removes potentially dangerous elements like `` tags. This is important for security when displaying user-generated content.

However, if you're using custom blocks that contain iframes (like the Video Block for YouTube/Vimeo embeds), you need to use `RenderType::UNSAFE_HTML` to preserve them:

```
// Video embeds will appear blank with sanitized HTML
$html = RichEditorUtil::render($content, RenderType::HTML); // ❌ iframes stripped

// Use UNSAFE_HTML to preserve video embeds
$html = RichEditorUtil::render($content, RenderType::UNSAFE_HTML); // ✅ iframes preserved
```

⚠️ **Security Warning:** Only use `UNSAFE_HTML` for trusted content (e.g., admin-created content). Never use it for user-generated content where XSS attacks are a concern.

### Generate a Table of Contents from content

[](#generate-a-table-of-contents-from-content)

Given a Filament `RichEditor` field or any HTML you pass to `RichContentRenderer`:

```
use Filament\Forms\Components\RichEditor\RichContentRenderer;

$renderer = RichContentRenderer::make('IntroTextDetails');

$toc = $renderer->toTableOfContents(maxDepth: 3);

// Example structure:
// [
//   [
//     'id' => 'intro',
//     'text' => 'Intro',
//     'depth' => 1,
//     'subs' => [
//       ['id' => 'details', 'text' => 'Details', 'depth' => 2],
//     ],
//   ],
// ]
```

The IDs are derived from the heading text and are deduplicated automatically (e.g., `intro`, `intro-1`, `intro-2`).

### Assign stable IDs to headings in an Editor

[](#assign-stable-ids-to-headings-in-an-editor)

If you’re working directly with a TipTap `Editor`, you can assign IDs to its headings:

```
use Filament\Forms\Components\RichEditor\RichContentRenderer;
use Tiptap\Core\Editor;

$editor = new Editor([
    'content' => 'IntroDetails',
]);

RichContentRenderer::make('')->processHeaderIds($editor, maxDepth: 3);

// The editor now contains heading nodes with unique `id` attributes.
```

### Factory Trait: BuildsRichEditorContent

[](#factory-trait-buildsricheditorcontent)

Use the included trait in your Laravel model factories to generate valid Rich Editor JSON structures for tests and seed data.

```
use Digitonic\FilamentRichEditorTools\Database\Factories\Concerns\BuildsRichEditorContent;
use Illuminate\Database\Eloquent\Factories\Factory;

class PostFactory extends Factory
{
    use BuildsRichEditorContent;

    public function definition(): array
    {
        return [
            'content' => $this->richEditorParagraphs(3),
        ];
    }
}
```

The trait provides three helpers:

- `richEditorParagraph(?string $text = null): array`
- `richEditorDocument(array $nodes): array`
- `richEditorParagraphs(int $count = 1): array`

Example output for `richEditorParagraph('Hello world')`:

```
{
  "type": "paragraph",
  "content": [
    {
      "type": "text",
      "text": "Hello world"
    }
  ]
}
```

Example output for `richEditorDocument([$this->richEditorParagraph('Hello world')])`:

```
{
  "type": "doc",
  "content": [
    {
      "type": "paragraph",
      "content": [
        {
          "type": "text",
          "text": "Hello world"
        }
      ]
    }
  ]
}
```

Example output shape for `richEditorParagraphs(2)`:

```
{
  "type": "doc",
  "content": [
    {
      "type": "paragraph",
      "content": [
        {
          "type": "text",
          "text": "Generated paragraph text..."
        }
      ]
    },
    {
      "type": "paragraph",
      "content": [
        {
          "type": "text",
          "text": "Generated paragraph text..."
        }
      ]
    }
  ]
}
```

`richEditorParagraphs()` uses `$this->faker`, so call it from within a standard Laravel `Factory` context where Faker is available.

Custom Blocks
-------------

[](#custom-blocks)

This package ships with four production-ready custom blocks that extend the Rich Editor's functionality:

### 1. Pros &amp; Cons Block

[](#1-pros--cons-block)

Creates visually appealing side-by-side comparison lists with checkmark and X icons.

**Features:**

- Separate repeatable fields for pros and cons
- Green/red color coding with appropriate icons
- Responsive two-column layout
- Collapsible interface in the editor

**Editor Configuration:**

- Add unlimited pros and cons via repeater fields
- Each item has a simple text input
- Items are collapsible and cloneable for easy management

**Output:**

- Clean, professional layout with branded colors
- Checkmark icons (✓) for pros, X icons (✗) for cons
- Responsive design that stacks on mobile

### 2. Video Block

[](#2-video-block)

Embeds YouTube and Vimeo videos with full responsive support.

**Features:**

- Automatic detection of YouTube and Vimeo URLs
- Responsive iframe embedding
- Optional caption support
- Secure iframe attributes (no-referrer, allowfullscreen)

**Supported Platforms:**

- YouTube (youtube.com, youtu.be)
- Vimeo (vimeo.com)
- Requires YouTube Watch Links, not embed links.

**Editor Configuration:**

- URL field for the video link
- Optional caption field

**Output:**

- Full-width responsive video player
- 16:9 aspect ratio maintained
- Caption displayed below video if provided

### 3. Twitter Embed Block

[](#3-twitter-embed-block)

Embeds Twitter/X posts using Twitter's native embedding system.

**Features:**

- Native Twitter widget integration
- Automatic URL conversion (x.com → twitter.com)
- Async script loading for performance

**Editor Configuration:**

- Single URL field for the Twitter/X post

**Output:**

- Native Twitter blockquote with full interactivity
- Preserves original post styling and functionality
- Responsive design

### 4. Table of Contents Block

[](#4-table-of-contents-block)

Dynamically generates a navigable table of contents from the current document.

**Features:**

- Automatic generation from document headings
- Hierarchical structure with proper indentation
- Click-to-navigate functionality
- Customizable depth levels

**Editor Configuration:**

- Automatically captures the current model and field information
- No manual configuration required

**Output:**

- Nested list structure with proper hierarchy
- Hover effects and visual feedback
- Smooth scroll navigation to sections
- Responsive indentation based on heading depth

### Using Custom Blocks

[](#using-custom-blocks)

All custom blocks are automatically registered when you use `RichEditorUtil::make()`:

```
use Digitonic\FilamentRichEditorTools\Filament\Utilities\RichEditorUtil;

// In your Filament form
RichEditorUtil::make('content')
    ->label('Page Content'),
```

Blocks appear in the "Custom Blocks" toolbar button and can be inserted anywhere in your content.

### Adding Your Own Custom Blocks

[](#adding-your-own-custom-blocks)

You can extend the available blocks by adding them to the configuration:

```
// config/filament-rich-editor-tools.php
return [
    'custom_blocks' => [
        App\Filament\CustomBlocks\MyCustomBlock::class,
        App\Filament\CustomBlocks\AnotherBlock::class,
    ],
];
```

Each custom block should extend `Filament\Forms\Components\RichEditor\RichContentCustomBlock` and implement:

- `getId()`: Unique identifier for the block
- `getLabel()`: Display name in the editor
- `configureEditorAction()`: Form fields for block configuration
- `toPreviewHtml()`: HTML shown in the editor
- `toHtml()`: Final rendered HTML output

### Automatic plugin registration

[](#automatic-plugin-registration)

The package service provider hooks into Laravel’s container and adds the Heading ID TipTap extension to every `RichContentRenderer` resolved by the container. You don’t need to manually add the plugin in your forms or pages.

Configuration
-------------

[](#configuration)

Publish the configuration file to customize the package behavior:

```
php artisan vendor:publish --tag=filament-rich-editor-tools-config
```

Publishing Views (Custom Block Blade Views)
-------------------------------------------

[](#publishing-views-custom-block-blade-views)

This package includes Blade views used by the built-in custom blocks (Pros &amp; Cons, Video, Twitter/X, Table of Contents).

If you want to override them, publish the views to your application:

```
php artisan vendor:publish --tag=filament-rich-editor-tools-views
```

This will publish to:

- `resources/views/vendor/filament-rich-editor-tools`

### Available Configuration Options

[](#available-configuration-options)

```
return [
    // Table of Contents settings
    'table_of_contents' => [
        'enabled' => true,
        'prefix' => '', // Add a prefix to all heading IDs (e.g., 'section-')
    ],

    // Add your own custom blocks
    'custom_blocks' => [
        App\Filament\CustomBlocks\CalloutBlock::class,
        App\Filament\CustomBlocks\CodeSnippetBlock::class,
        // Add as many as needed
    ],
];
```

### Configuration Details

[](#configuration-details)

- **`table_of_contents.enabled`**: Controls whether TOC functionality is active
- **`table_of_contents.prefix`**: Adds a prefix to all generated heading IDs for namespace separation
- **`custom_blocks`**: Array of custom block classes that extend the available blocks in your Rich Editor

The package automatically merges your custom blocks with the four built-in blocks (Pros &amp; Cons, Video, Twitter Embed, Table of Contents).

Testing
-------

[](#testing)

We recommend writing feature tests around your Filament pages/components and asserting the TOC output when relevant.

### Testing Table of Contents Generation

[](#testing-table-of-contents-generation)

Example using Pest:

```
use Filament\Forms\Components\RichEditor\RichContentRenderer;

it('builds a nested table of contents', function () {
    $renderer = RichContentRenderer::make('IntroDetailsMore');
    $toc = $renderer->toTableOfContents();

    expect($toc)
        ->toBeArray()
        ->and($toc[0]['text'] ?? null)->toBe('Intro')
        ->and($toc[0]['subs'][0]['text'] ?? null)->toBe('Details');
});
```

### Testing Custom Blocks in Filament

[](#testing-custom-blocks-in-filament)

```
use Digitonic\FilamentRichEditorTools\Filament\Utilities\RichEditorUtil;

it('can render pros and cons block', function () {
    $content = [
        'type' => 'doc',
        'content' => [
            [
                'type' => 'prosAndConsBlock',
                'attrs' => [
                    'pros' => [['text' => 'Great performance']],
                    'cons' => [['text' => 'Expensive']]
                ]
            ]
        ]
    ];

    $rendered = RichEditorUtil::render($content);

    expect($rendered)
        ->toContain('Great performance')
        ->toContain('Expensive');
});
```

### Testing Video Embedding

[](#testing-video-embedding)

```
use Digitonic\FilamentRichEditorTools\Support\EmbeddableVideo;

it('can embed youtube videos', function () {
    $video = new EmbeddableVideo('https://www.youtube.com/watch?v=dQw4w9WgXcQ');

    expect($video->isEmbeddable())->toBeTrue();
    expect($video->getEmbedUrl())->toContain('youtube.com/embed/');
});
```

Run your tests:

```
php artisan test --filter="rich editor"
```

Contributing
------------

[](#contributing)

Contributions are welcome. Please open issues or PRs describing your use case and proposed changes.

License
-------

[](#license)

The MIT License (MIT). See `LICENSE.md` for details.

###  Health Score

45

—

FairBetter than 92% of packages

Maintenance83

Actively maintained with recent releases

Popularity20

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity57

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 97.8% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~4 days

Total

7

Last Release

90d ago

Major Versions

1.0.5 → 2.0.02026-02-11

PHP version history (2 changes)1.0.0PHP ^8.2|^8.3|^8.4

2.0.0PHP ^8.2|^8.3|^8.4|^8.5

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/1104549?v=4)[Steven Richardson](/maintainers/richdynamix)[@richdynamix](https://github.com/richdynamix)

---

Top Contributors

[![SOD96](https://avatars.githubusercontent.com/u/9489645?v=4)](https://github.com/SOD96 "SOD96 (44 commits)")[![richdynamix](https://avatars.githubusercontent.com/u/1104549?v=4)](https://github.com/richdynamix "richdynamix (1 commits)")

---

Tags

laraveldigitonicfilament-rich-editor-tools

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/digitonic-filament-rich-editor-tools/health.svg)

```
[![Health](https://phpackages.com/badges/digitonic-filament-rich-editor-tools/health.svg)](https://phpackages.com/packages/digitonic-filament-rich-editor-tools)
```

###  Alternatives

[guava/calendar

Adds support for vkurko/calendar to Filament PHP.

298241.0k3](/packages/guava-calendar)[pboivin/filament-peek

Full-screen page preview modal for Filament

253319.6k12](/packages/pboivin-filament-peek)[dotswan/filament-map-picker

Easily pick and retrieve geo-coordinates using a map-based interface in your Filament applications.

124139.3k2](/packages/dotswan-filament-map-picker)[creagia/filament-code-field

A Filamentphp input field to edit or view code data.

58289.3k3](/packages/creagia-filament-code-field)[swisnl/filament-backgrounds

Beautiful backgrounds for Filament auth pages

54149.2k6](/packages/swisnl-filament-backgrounds)[hydrat/filament-table-layout-toggle

Filament plugin adding a toggle button to tables, allowing user to switch between Grid and Table layouts.

6292.3k1](/packages/hydrat-filament-table-layout-toggle)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
