Skip to main content
← Back to Table of Contents

Summary

JSON-first rich text editor built on Filament RichEditor / TipTap, with a FLEX interface, Hugeicons, content limits with live feedback, responsive images, optional Spatie Media Library, YouTube embeds, custom blocks, fullscreen, autosave, paste cleanup, and a keyboard-accessible toolbar. The field inherits the document features and configuration of Filament Rich Editor. FLEX supplies the interface and its additional upload, rendering and editing options described below. Options introduced in newer Filament releases require that release in your application.

Quick start

Content is stored as a TipTap JSON document. Render HTML on the frontend with makeFlexRichContentRenderer() (see Rendering HTML).

Filament configuration with the FLEX interface

Use the inherited configuration methods on FlexRichEditor; you do not need a second native editor. For example:
The interface adapts to the panel’s light or dark theme. secondary has a subtle gray background, primary and soft use the field surface, and flat has a transparent surface. Tool buttons with visible labels expand to fit their text.

Merge tags and custom blocks

Enable merge tags to let authors insert placeholders:
Custom block classes extend Filament’s RichContentCustomBlock. Configure them on the same field; FLEX displays their picker in its own panel. In Filament versions that support grouped, searchable blocks, you can also use:
The block’s configuration action and document format remain compatible with Filament. Mentions, text colors, custom tools/plugins, floating toolbars, attachment providers and HTML or JSON state also use the inherited API; consult the version-specific Filament documentation for their complete configuration.

Configuration catalog (package API)

FlexRichEditor-specific options only. The field extends Filament RichEditor; inherited Filament APIs are not duplicated here.

Shell & field chrome

Editor UX

Toolbar

Static helpers (presets): getFlexDefaultToolbarButtons(), getFlexFullToolbarButtons(), getFlexDefaultFloatingToolbars(), getFlexExtraTools(), getNativeComparisonToolbarButtons(). To override button layout, use Filament’s toolbarButtons() / floatingToolbars() / tools() with these presets — see Filament Rich Editor.

File attachments & images (package layer)

Requires Filament fileAttachments() / disk options to be enabled first. This table lists Flex processing and cleanup on top of that baseline.

HTML rendering

Built-in plugins (automatic): block images (always), YouTube (when youtube()), paste cleanup (when pasteCleanup()).

Shell variants

primary

secondary (default)

soft

flat


Shell sizes

sm

md (default)

lg


Focus outline


Word count


JSON debug badge


Content limits

Footer states: ok → warning (≥90% of max) → danger (over limit). Form save still runs server validation.

Hard limits — block typing past max

Hard mode calls editor.commands.undo() when the user exceeds max characters or words.

Min characters only

Max characters only

Max words only


Reading time

Config: config('filament-flex-fields.rich_editor.reading_time_words_per_minute').

Fullscreen


Distraction-free

Hides clearFormatting and clearContent in the toolbar while fullscreen is active.

Autosave

Saves editor JSON to localStorage. On reload, prompts to restore if a newer draft exists.
Default key pattern: {statePath}::{model:id|create}::user:{id}.

Paste cleanup


YouTube embeds

Requires ->youtube(). Adds toolbar button + TipTap extension + paste handler for YouTube URLs.
Accepted URL shapes: youtube.com/watch?v=, youtu.be/, youtube.com/embed/, youtube.com/shorts/. Rendered HTML preserves data-youtube-video iframes through FlexRichContentRenderer::toHtml() sanitization.

Block images (automatic)

FlexRichEditorBlockImagePlugin is always registered. Images inserted in the editor are block-level (not inline with paragraph text). No configuration required.

Image overlay (editor only)

When file attachments are enabled, selecting an image shows Edit and Delete controls (top-right overlay). Not included in frontend HTML output.
  • Edit → opens Filament attachFiles action (alt text, replace).
  • Delete → removes image from document.

Toolbar presets

Default Flex toolbar (no attachFiles)

Groups: undo/redo, formatting, headings dropdown, alignment dropdown, blockquote/code, lists dropdown, link, clear formatting/content.

Full toolbar (with attachments button)

Custom toolbar

Toolbar roles

Presets in config('filament-flex-fields.rich_editor.toolbar_roles').

Author

Editor

Admin

Custom role (after publishing config)

Publish config:

Disabled toolbar tools

Works with string button names from toolbar groups. flexFullscreen and plugin tools (youtube) use their tool names.

Floating toolbars

Default paragraph bubble (bold, italic, underline, strike, link). Hidden when an image is selected.

Custom tools

Flex adds Hugeicons tools via FlexRichEditor::getFlexExtraTools():
  • clearFormatting — clear nodes + marks
  • clearContent — empty document
When fullscreen() is enabled, flexFullscreen tool is appended automatically.

File attachments

Uploads use Filament’s attachment API (fileAttachments(), disk, directory, visibility). Flex adds scoped paths, optimization, variants, and orphan cleanup on top. Attachments are enabled when fileAttachments(true) or the toolbar includes attachFiles and Filament resolves hasFileAttachments().

Visibility


Scoped attachment directories

scopedAttachmentDirectory('rich-editor') resolves:
  • {prefix}/{model}/{id}/ when editing a record
  • {prefix}/drafts/{userId}/ on create forms

Images only

Restricts accepted MIME types to images (JPEG, PNG, GIF, WebP).

Max attachment size


Single-pass image optimization

Without named variants — resizes/optimizes the master file on upload.

Named image variants

The default disk uploader creates a WebP thumbnail with a maximum long edge of 250 px and a WebP master with a maximum long edge of 1500 px. Small images are not enlarged. The optimized master replaces the disk original only after all outputs and their manifest have been written successfully.
The attachment modal uses FLEX File Upload and FLEX Text Input for alternative text. Its submit button waits for temporary uploads to finish. The editor previews the temporary image; permanent variants are generated when the form saves the attachment. On a disk, a master such as photo.webp has a photo__thumb.webp thumbnail and a photo.webp.flex-variants.json manifest. Generation supports local and stream-capable remote disks, preserves visibility, and stages all variants privately before publication. Raster processing has limits of 64 MiB per input and 50 megapixels; inputs exceeding these limits fail instead of starting unbounded processing.

Array config

Fluent RichEditorImageVariant objects

Variant keys: max_long_edge, max_width, max_height, webp, master, optimize.

Automatic attachment cleanup

Native disk (default on)

On save: compares image IDs in JSON before/after; deletes removed masters, variants, and .flex-variants.json manifests. Cleanup is limited to attachments removed from this document. Other files in the same directory are preserved.

Spatie Media Library

Disk pruner is skipped. Filament calls FileAttachmentProvider::cleanUpFileAttachments(exceptIds: [...]) on save.

Responsive images in HTML output

Lazy images on/off

Responsive srcset on/off

When variants are configured, responsiveImages() defaults to on if not set explicitly.

Image sizes attribute


Rendering HTML

Always use makeFlexRichContentRenderer() so disk, variants, plugins (YouTube), and lazy loading match the field.

In Filament infolist / table column

Standalone renderer

Example output

Blade view

Inertia / API controller


Alt text required


Accessibility

Built-in without extra configuration:

Spatie Media Library (optional)

Spatie keeps ownership of originals, conversions and queued jobs. The uploader does not resize its original before passing it to Spatie. Register the desired conversions on your media model; field configuration alone does not register model conversions. Until a queued conversion exists, preview/rendering falls back to the original.

1. Model — register conversions

The helper creates every named Spatie conversion, including large. On Spatie, master identifies the preferred display variant; it does not replace or delete the original. Omit queued: true for synchronous conversions.

2. Form

3. Render


Complete example: Filament Resource


Configuration recipes

Minimal blog post

Production article (native disk)

Author role (limited toolbar)


Package config

config/filament-flex-fields.php:
Publish:

Translations

Package strings: filament-flex-fields::default.rich_editor.* in resources/lang/en/default.php and resources/lang/pl/default.php. Toolbar labels reuse Filament: filament-forms::components.rich_editor.tools.*.

Publish translations

Key reference


Testing

PHP (package)

JavaScript unit tests

Playwright E2E (playground)


Playground

/admin/flex-fields/flex-rich-editor — see Playground. Slug: flex-rich-editor Includes:
  • Full Article body demo (attachments, variants, limits, YouTube, fullscreen, autosave)
  • Variant grid: compact / secondary / soft / flat
  • Attachments-only and full-toolbar sections

Assets (CSS & JS)

Each field loads its own CSS bundle and Alpine component on demand (x-fff-load). Optional support scripts load only when configured.

Does it duplicate Filament’s rich editor?

FLEX owns the editor shell, toolbar and supporting modules. The shell lazily imports Filament’s registered rich-editor runtime and awaits its initialization; it does not bundle a second copy of the native runtime. Multiple FLEX editors share that dependency. The playground contains only FLEX examples. The scoped rich-editor-field.css stylesheet owns the FLEX chrome. Built-in controls use Hugeicons with a consistent stroke width of 2; document content is outside this chrome rule. The contenteditable uses aria-labelledby to reference its visible field label rather than an invalid HTML label[for] association.

Performance notes

  • Footer stats use requestAnimationFrame batching (not per-keystroke DOM thrashing).
  • Image overlay sync runs on selection changes only.
  • Attachment manifest reads are cached per request during HTML rendering.
  • CI checks the emitted shell and shared dependency graph against the package bundle budgets. The Filament runtime remains a separately loaded dependency.

Requirements & optional packages


Filament RichEditor baseline

FlexRichEditor extends Filament\Forms\Components\RichEditor. Options not documented on this page behave as in Filament.
Last modified on October 20, 2026