Introduction
Every rich_text_editor form field — Shop product/category descriptions, blog comment bodies, or a custom module's own HTML field — renders through one shared, zero-dependency component: Zero\Support\Forms\RichTextEditorField, backed by a single contenteditable template at src/Modules/Admin/Views/editor.php. Every instance used to get the exact same fixed toolbar (bold, italic, underline, lists, link, table, clear-formatting), whether the field needed all of that or not.
Opting a Field Into a Reduced Toolbar
The editor template now resolves its button set from a small $toolbarSets registry, keyed by a toolbar value read straight out of the field's own config array — so any model's getConfig() can opt in with one extra key, no new field type required:
'description' => [
'type' => 'rich_text_editor',
'toolbar' => 'basic',
'label' => 'Description',
'editable' => true,
],Omitting toolbar entirely keeps the original full button set, so every pre-existing rich_text_editor field elsewhere in the codebase is unaffected.
The Toolbar Registry (editor.php)
$buttons = [
'bold' => '<button type="button" data-cmd="bold"><strong>B</strong></button>',
'italic' => '<button type="button" data-cmd="italic"><em>I</em></button>',
'underline' => '<button type="button" data-cmd="underline"><u>U</u></button>',
'insertUnorderedList' => '<button type="button" data-cmd="insertUnorderedList">UL</button>',
'insertOrderedList' => '<button type="button" data-cmd="insertOrderedList">OL</button>',
'createLink' => '<button type="button" data-cmd="createLink">A</button>',
'insertTable' => '<button type="button" data-cmd="insertTable" title="Insert Table">Table</button>',
'removeFormat' => '<button type="button" data-cmd="removeFormat">Clear</button>',
];
$toolbarSets = [
'full' => array_keys($buttons),
'basic' => ['bold', 'italic', 'underline', 'insertUnorderedList', 'insertOrderedList', 'createLink', 'removeFormat'],
];
$activeButtons = $toolbarSets[$toolbar ?? 'full'] ?? $toolbarSets['full'];
Adding a New Preset
A new preset is just another array key naming a subset of $buttons — e.g. a 'minimal' preset with only ['bold', 'italic', 'createLink']. No JavaScript changes are ever required: public/assets/js/admin.js's toolbar handler is fully generic — it delegates off whichever [data-cmd] buttons actually exist in the rendered DOM rather than hardcoding a fixed button list, so it automatically adapts to whatever editor.php ends up printing.
The Toolbar Is UX, Not a Security Boundary
Trimming the toolbar only changes which buttons an editor sees — it does nothing to stop a pasted <table>, a browser extension, or a direct API write from landing block-level HTML in a field's stored value regardless of preset. The rendering side must independently enforce whatever tag set it actually wants to allow, with its own allow-list sanitizer — matching the toolbar's button set is a courtesy to the editor, not a substitute for sanitizing on render.