Rich editor
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')

Configuring Livewire's maximum nesting depth
The rich editor synchronizes its TipTap document with Livewire as nested data. Livewire limits nested property paths to 10 levels by default, which may not be enough for structures such as lists and tables. If you encounter a Livewire\Exceptions\MaxNestingDepthExceededException and your application does not already have a config/livewire.php file, publish Livewire's configuration file:
php artisan livewire:publish --config
The command overwrites an existing config/livewire.php file, so skip it if you have already published the configuration.
Then, increase the existing max_nesting_depth setting in config/livewire.php. For example, a depth of 32 allows room for deeply nested rich content:
'payload' => [
// ...
'max_nesting_depth' => 32,
],
Only change the max_nesting_depth value in the existing payload array, so that you preserve Livewire's other version-specific payload settings.
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 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 aleadclass 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.
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.
Learn more about utility injection.| Utility | Type | Parameter | Description |
|---|---|---|---|
| Field | Filament\Forms\Components\Field | $component | The current field component instance. |
| Get function | Filament\Schemas\Components\Utilities\Get | $get | A function for retrieving values from the current form data. Validation is not run. |
| Livewire | Livewire\Component | $livewire | The Livewire component instance. |
| Eloquent model FQN | ?string<Illuminate\Database\Eloquent\Model> | $model | The Eloquent model FQN for the current schema. |
| Operation | string | $operation | The current operation being performed by the schema. Usually <code>create</code>, <code>edit</code>, or <code>view</code>. |
| Raw state | mixed | $rawState | The current value of the field, before state casts were applied. Validation is not run. |
| Eloquent record | ?Illuminate\Database\Eloquent\Model | $record | The Eloquent record for the current schema. |
| State | mixed | $state | The current value of the field. Validation is not run. |
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.
Setting the height
You may control the editor's height by defining the minHeight() and maxHeight() methods, which accept any CSS length value:
use Filament\Forms\Components\RichEditor;
RichEditor::make('content')
->minHeight('12rem')
->maxHeight('24rem')
The editor has a minimum height of 10rem by default. Once the content exceeds maxHeight(), the editor stops growing and becomes scrollable. Each method may be used on its own — minHeight() sets a starting height while still allowing the editor to grow, and maxHeight() caps how tall it may become. Pass null to minHeight() to use the editor's intrinsic 3rem minimum height, or to maxHeight() to remove the cap. These constraints also apply when the editor is disabled.
As well as allowing static values, the minHeight() and maxHeight() methods also accept functions to dynamically calculate them. You can inject various utilities into the functions as parameters.
Learn more about utility injection.| Utility | Type | Parameter | Description |
|---|---|---|---|
| Field | Filament\Forms\Components\Field | $component | The current field component instance. |
| Get function | Filament\Schemas\Components\Utilities\Get | $get | A function for retrieving values from the current form data. Validation is not run. |
| Livewire | Livewire\Component | $livewire | The Livewire component instance. |
| Eloquent model FQN | ?string<Illuminate\Database\Eloquent\Model> | $model | The Eloquent model FQN for the current schema. |
| Operation | string | $operation | The current operation being performed by the schema. Usually <code>create</code>, <code>edit</code>, or <code>view</code>. |
| Raw state | mixed | $rawState | The current value of the field, before state casts were applied. Validation is not run. |
| Eloquent record | ?Illuminate\Database\Eloquent\Model | $record | The Eloquent record for the current schema. |
| State | mixed | $state | The current value of the field. Validation is not run. |
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.





