Weave Code
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

Forms Laravel Package

filament/forms

Filament Forms is a Laravel package for building powerful, reactive admin forms with a fluent, component-based API. Create fields, layouts, validation, conditional logic, and dynamic interactions quickly, with tight Livewire integration and great DX for panels and apps.

View on GitHub
Deep Wiki
Context7

title: Rich editor

import Aside from "@components/Aside.astro" import AutoScreenshot from "@components/AutoScreenshot.astro" import UtilityInjection from "@components/UtilityInjection.astro"

Introduction

The rich editor allows you to edit and preview HTML content, as well as upload images. It uses TipTap as the underlying editor.

use Filament\Forms\Components\RichEditor;

RichEditor::make('content')

Storing content as JSON

By default, the rich editor stores content as HTML. If you would like to store the content as JSON instead, you can use the json() method:

use Filament\Forms\Components\RichEditor;

RichEditor::make('content')
    ->json()

The JSON is in TipTap's format, which is a structured representation of the content.

If you're saving the JSON content using Eloquent, you should be sure to add an array cast to the model property:

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    /**
     * [@return](https://github.com/return) array<string, string>
     */
    protected function casts(): array
    {
        return [
            'content' => 'array',
        ];
    }

    // ...
}

Customizing the toolbar buttons

You may set the toolbar buttons for the editor using the toolbarButtons() method. The options shown here are the defaults:

use Filament\Forms\Components\RichEditor;

RichEditor::make('content')
    ->toolbarButtons([
        ['bold', 'italic', 'underline', 'strike', 'subscript', 'superscript', 'link'],
        ['h2', 'h3'],
        ['alignStart', 'alignCenter', 'alignEnd'],
        ['blockquote', 'codeBlock', 'bulletList', 'orderedList'],
        ['table', 'attachFiles'], // The `customBlocks` and `mergeTags` tools are also added here if those features are used.
        ['undo', 'redo'],
    ])

Each nested array in the main array represents a group of buttons in the toolbar.

Additional tools available in the toolbar include:

  • h1 - Applies the "h1" tag to the text.
  • h4 - Applies the "h4" tag to the text.
  • h5 - Applies the "h5" tag to the text.
  • h6 - Applies the "h6" tag to the text.
  • alignJustify - Justifies the text.
  • clearFormatting - Clears all formatting from the selected text.
  • details - Inserts a <details> tag, which allows users to create collapsible sections in their content.
  • grid - Inserts a grid layout into the editor, allowing users to create responsive columns of content.
  • gridDelete - Deletes the current grid layout.
  • highlight - Highlights the selected text with a <mark> tag around it.
  • horizontalRule - Inserts a horizontal rule.
  • lead - Applies a lead class around the text, which is typically used for the first paragraph of an article.
  • paragraph - Sets the current block to a paragraph, removing any heading formatting.
  • small - Applies the <small> tag to the text, which is typically used for small print or disclaimers.
  • code - Format the selected text as inline code.
  • textColor - Changes the text color of the selected text.
  • table - Creates a table in the editor with a default layout of 3 columns and 2 rows, with the first row configured as a header row.
  • tableAddColumnBefore - Adds a new column before the current column.
  • tableAddColumnAfter - Adds a new column after the current column.
  • tableDeleteColumn - Deletes the current column.
  • tableAddRowBefore - Adds a new row above the current row.
  • tableAddRowAfter - Adds a new row below the current row.
  • tableDeleteRow - Deletes the current row.
  • tableMergeCells - Merges the selected cells into one cell.
  • tableSplitCell - Splits the selected cell into multiple cells.
  • tableToggleHeaderRow - Toggles the header row of the table.
  • tableToggleHeaderCell - Toggles the header cell of the table.
  • tableDelete - Deletes the table.

<UtilityInjection set="formFields" version="5.x">As well as allowing a static value, the toolbarButtons() method also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.</UtilityInjection>

Customizing floating toolbars

If your toolbar is too full, you can use a floating toolbar to show certain tools in a toolbar below the cursor, only when the user is inside a specific node type. This allows you to keep the main toolbar clean while still providing access to additional tools when needed.

You can customize the floating toolbars that appear when your cursor is placed inside a specific node by using the floatingToolbars() method.

In the example below, a floating toolbar appears when the cursor is inside a paragraph node. It shows bold, italic, and similar buttons. When the cursor is in a heading node, it displays heading-related buttons, and when inside a table, it shows table-specific controls.

use Filament\Forms\Components\RichEditor;

RichEditor::make('content')
    ->floatingToolbars([
        'paragraph' => [
            'bold', 'italic', 'underline', 'strike', 'subscript', 'superscript',
        ],
        'heading' => [
            'h1', 'h2', 'h3',
        ],
        'table' => [
            'tableAddColumnBefore', 'tableAddColumnAfter', 'tableDeleteColumn',
            'tableAddRowBefore', 'tableAddRowAfter', 'tableDeleteRow',
            'tableMergeCells', 'tableSplitCell',
            'tableToggleHeaderRow', 'tableToggleHeaderCell',
            'tableDelete',
        ],
    ])

Grouping toolbar buttons into dropdowns

You may group related toolbar buttons into a dropdown menu using ToolbarButtonGroup. The first argument is a label used for the dropdown's tooltip and accessibility, and the second argument is an array of button names to include in the dropdown:

use Filament\Forms\Components\RichEditor;
use Filament\Forms\Components\RichEditor\ToolbarButtonGroup;

RichEditor::make('content')
    ->toolbarButtons([
        ['bold', 'italic', 'underline', 'strike'],
        [ToolbarButtonGroup::make('Paragraph', ['paragraph', 'h1', 'h2', 'h3'])],
        [ToolbarButtonGroup::make('Alignment', ['alignStart', 'alignCenter', 'alignEnd', 'alignJustify'])],
        ['blockquote', 'codeBlock', 'bulletList', 'orderedList'],
        ['undo', 'redo'],
    ])

By default, the first button's icon is used as the dropdown trigger, and it updates reactively to reflect the currently active button. Clicking on the trigger reveals the grouped buttons.

You can set a fixed icon for the dropdown trigger using the icon() method. When a custom icon is set, the trigger icon remains static and does not change based on the active button:

use Filament\Forms\Components\RichEditor;
use Filament\Forms\Components\RichEditor\ToolbarButtonGroup;

RichEditor::make('content')
    ->toolbarButtons([
        ['bold', 'italic', 'underline', 'strike'],
        [ToolbarButtonGroup::make('Heading', ['h1', 'h2', 'h3'])->icon('fi-o-heading')],
        [ToolbarButtonGroup::make('Alignment', ['alignStart', 'alignCenter', 'alignEnd', 'alignJustify'])],
        ['blockquote', 'codeBlock', 'bulletList', 'orderedList'],
        ['undo', 'redo'],
    ])

Using textual dropdown toolbar buttons

By default, dropdown toolbar buttons display icons only. If you'd like to show text labels alongside icons in the dropdown items, you can use the textualButtons() method on a ToolbarButtonGroup:

use Filament\Forms\Components\RichEditor;
use Filament\Forms\Components\RichEditor\ToolbarButtonGroup;

RichEditor::make('content')
    ->toolbarButtons([
        ['bold', 'italic', 'underline', 'strike', 'link'],
        [ToolbarButtonGroup::make('Paragraph', ['paragraph', 'h1', 'h2', 'h3'])->textualButtons()],
        [ToolbarButtonGroup::make('Alignment', ['alignStart', 'alignCenter', 'alignEnd', 'alignJustify'])],
        ['blockquote', 'codeBlock', 'bulletList', 'orderedList'],
        ['undo', 'redo'],
    ])

In this example, the Paragraph dropdown items display their icon alongside a text label (e.g., "Paragraph", "Heading 1"). The Alignment dropdown remains icon-only.

Customizing text colors

The rich editor includes a text color tool for styling inline text. By default, it uses the Tailwind CSS color palette. In light mode, the 600 shades are applied to text, and in dark mode, the 400 shades are used.

You can customize which colors are available in the picker using the textColors() method:

use Filament\Forms\Components\RichEditor;

RichEditor::make('content')
    ->textColors([
        '#ef4444' => 'Red',
        '#10b981' => 'Green',
        '#0ea5e9' => 'Sky',
    ])

If you would like to define different colors for light and dark mode, you can use the a TextColor object to define the color:

use Filament\Forms\Components\RichEditor;
use Filament\Forms\Components\RichEditor\TextColor;

RichEditor::make('content')
    ->textColors([
        'brand' => TextColor::make('Brand', '#0ea5e9'),
        'warning' => TextColor::make('Warning', '#f59e0b', darkColor: '#fbbf24'),
    ])

If you would like to add new colors onto the existing Tailwind palette, you can merge your colors into the TextColor::getDefaults() array:

use Filament\Forms\Components\RichEditor;
use Filament\Forms\Components\RichEditor\TextColor;

RichEditor::make('content')
    ->textColors([
        'brand' => TextColor::make('Brand', '#0ea5e9'),
        'warning' => TextColor::make('Warning', '#f59e0b', darkColor: '#fbbf24'),
        ...TextColor::getDefaults(),
    ])

When you use a TextColor object, the key of the array becomes the stored data-color attribute on the <span> tag, allowing you to reference the color in your CSS if needed. When you use the color as the array values, the actual color value (e.g., a HEX string) is stored as the data-color attribute.

You can also pass textColors() to the content renderer and rich content attribute so that server-side rendering matches your editor configuration.

You can also allow users to pick custom colors that aren't in the predefined list by using the customTextColors() method:

use Filament\Forms\Components\RichEditor;

RichEditor::make('content')
    ->textColors([
        // ...
    ])
    ->customTextColors()

You do not need to use customTextColors() on the content renderer, as it will automatically render any custom colors that are used in the content.

Rendering rich content

If you're storing content as JSON instead of HTML, or your content requires processing to inject private image URLs or similar, you'll need to use the RichContentRenderer tool in Filament to output HTML:

use Filament\Forms\Components\RichEditor\RichContentRenderer;

RichContentRenderer::make($record->content)->toHtml()

The toHtml() method returns a string. If you would like to output HTML in a Blade view without escaping the HTML, you can echo the RichContentRender object without calling toHtml():

{{ \Filament\Forms\Components\RichEditor\RichContentRenderer::make($record->content) }}

If you have configured the file attachments behavior of the editor to change the disk or visibility of the uploaded files, you must also pass these settings to the renderer to ensure that the correct URLs are generated:

use Filament\Forms\Components\RichEditor\RichContentRenderer;

RichContentRenderer::make($record->content)
    ->fileAttachmentsDisk('s3')
    ->fileAttachmentsVisibility('private')
    ->toHtml()

If you are using custom blocks in the rich editor, you can pass an array of custom blocks to the renderer to ensure that they are rendered correctly:

use Filament\Forms\Components\RichEditor\RichContentRenderer;

RichContentRenderer::make($record->content)
    ->customBlocks([
        HeroBlock::class => [
            'categoryUrl' => $record->category->getUrl(),
        ],
        CallToActionBlock::class,
    ])
    ->toHtml()

If you are using merge tags, you can pass an array of values to replace the merge tags with:

use Filament\Forms\Components\RichEditor\RichContentRenderer;

RichContentRenderer::make($record->content)
    ->mergeTags([
        'name' => $record->user->name,
        'today' => now()->toFormattedDateString(),
    ])
    ->toHtml()

If you are using custom text colors, you can pass an array of colors to the renderer to ensure that the colors are rendered correctly:

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

RichContentRenderer::make($record->content)
    ->textColors([
        'brand' => TextColor::make('Brand', '#0ea5e9', darkColor: '#38bdf8'),
    ])
    ->toHtml();

Styling the rendered content

The rich editor HTML uses a combination of HTML elements, CSS classes, and inline styles to style the content, depending on the features used in the editor. If you render the content in a Filament table column or infolist entry with prose(), Filament will automatically apply the necessary styles for you. If you are outputting the content in your own Blade view, you may need to add some additional styles to ensure that the content is styled correctly.

One way of styling the content is to use Tailwind CSS Typography. This plugin provides a set of pre-defined styles for common HTML elements, such as headings, paragraphs, lists, and tables. You can apply these styles to a container element using the prose class:

<div class="prose dark:prose-invert">
    {!! \Filament\Forms\Components\RichEditor\RichContentRenderer::make($record->content) !!}
</div>

However, some features, such as the grid layout and text colors, require additional styles that are not included in the Tailwind CSS Typography plugin. Filament also includes its own fi-prose CSS class that adds these additional styles. Any app that loads Filament's vendor/filament/support/resources/css/index.css CSS will have access to this class. The styling is different to the prose class, but fits with Filament's design system better:

<div class="fi-prose">
    {!! \Filament\Forms\Components\RichEditor\RichContentRenderer::make($record->content) !!}
</div>

Security

By default, the editor outputs raw HTML, and sends it to the backend. Attackers are able to intercept the value of the component and send a different raw HTML string to the backend. As such, it is important that when outputting the HTML from a rich editor, it is sanitized; otherwise your site may be exposed to Cross-Site Scripting (XSS) vulnerabilities.

When Filament outputs raw HTML from the database in components such as TextColumn and TextEntry, it sanitizes it to remove any dangerous JavaScript. However, if you are outputting the HTML from a rich editor in your own Blade view, this is your responsibility. One option is to use Filament's sanitizeHtml() helper to do this, which is the same tool we use to sanitize HTML in the components mentioned above:

{!! str($record->content)->sanitizeHtml() !!}

If you're storing content as JSON instead of HTML, or your content requires processing to inject private image URLs or similar, you can use the content renderer to output HTML. This will automatically sanitize the HTML for you, so you don't need to worry about it.

Uploading images to the editor

By default, uploaded images are stored publicly on your storage disk, so that the rich content stored in the database can be output easily anywhere. You may customize how images are uploaded using configuration methods:

use Filament\Forms\Components\RichEditor;

RichEditor::make('content')
    ->fileAttachmentsDisk('s3')
    ->fileAttachmentsDirectory('attachments')
    ->fileAttachmentsVisibility('private')

<UtilityInjection set="formFields" version="5.x">As well as allowing static values, the fileAttachmentsDisk(), fileAttachmentsDirectory(), and fileAttachmentsVisibility() methods also accept functions to dynamically calculate them. You can inject various utilities into the function as parameters.</UtilityInjection>

Using private images in the editor

Using private images in the editor adds a layer of complexity to the process, since private images cannot be accessed directly via a permanent URL. Each time the editor is loaded or its content is rendered, temporary URLs need to be generated for each image, which are never stored in the database. Instead, Filament adds a data-id attribute to the image tags, which contains an identifier for the image in the storage disk, so that a temporary URL can be generated on demand.

When rendering the content using private images, ensure that you are using the RichContentRenderer tool in Filament to output HTML:

use Filament\Forms\Components\RichEditor\RichContentRenderer;

RichContentRenderer::make($record->content)
    ->fileAttachmentsDisk('s3')
    ->fileAttachmentsVisibility('private')
    ->toHtml()

Validating uploaded images

You may use the fileAttachmentsAcceptedFileTypes() method to control a list of accepted mime types for uploaded images. By default, image/png, image/jpeg, image/gif, and image/webp are accepted:

use Filament\Forms\Components\RichEditor;

RichEditor::make('content')
    ->fileAttachmentsAcceptedFileTypes(['image/png', 'image/jpeg'])

You may use the fileAttachmentsMaxSize() method to control the maximum file size for uploaded images. The size is specified in kilobytes. By default, the maximum size is 12288 KB (12 MB):

use Filament\Forms\Components\RichEditor;

RichEditor::make('content')
    ->fileAttachmentsMaxSize(5120) // 5 MB

Allowing users to resize images

By default, images in the editor cannot be resized by the user. You may enable image resizing using the resizableImages() method:

use Filament\Forms\Components\RichEditor;

RichEditor::make('content')
    ->resizableImages()

When enabled, users can resize images by clicking on them and dragging the resize handles. The aspect ratio is always preserved when resizing.

<UtilityInjection set="formFields" version="5.x">As well as allowing a static value, the resizableImages() method also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.</UtilityInjection>

Using custom blocks

Custom blocks are elements that users can drag and drop into the rich editor. You can define custom blocks that user can insert into the rich editor using the customBlocks() method:

use Filament\Forms\Components\RichEditor;

RichEditor::make('content')
    ->customBlocks([
        HeroBlock::class,
        CallToActionBlock::class,
    ])

To create a custom block, you can use the following command:

php artisan make:filament-rich-content-custom-block HeroBlock

Each block needs a corresponding class that extends the Filament\Forms\Components\RichEditor\RichContentCustomBlock class. The getId() method should return a unique identifier for the block, and the getLabel() method should return the label that will be displayed in the editor's side panel:

use Filament\Forms\Components\RichEditor\RichContentCustomBlock;

class HeroBlock extends RichContentCustomBlock
{
    public static function getId(): string
    {
        return 'hero';
    }

    public static function getLabel(): string
    {
        return 'Hero section';
    }
}

When a user drags a custom block into the editor, you can choose to open a modal to coll.....

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.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport
twbs/bootstrap4