arm092/laravel-rich-text-editor
A secure rich text editor for Laravel forms with Blade and Livewire components, Alpine.js and Tailwind support, sanitized HTML storage, responsive images and tables, plus basic or enhanced code view. Config and prebuilt assets included.
Minimal setup
composer update vendor/package # land on v1.3.11
php artisan vendor:publish --tag=package-assets --force
php artisan vendor:publish --tag=package-config # only if you have no published config yet
php artisan view:clear && php artisan config:clear
The --force on assets matters: the new toolbar buttons (copyStyle, pasteStyle) ship as editor plugin/asset code. If you only bump the Composer constraint and skip the asset republish, the buttons will appear in a profile but silently do nothing (or throw a missing-module error in the browser console).
Where to look first
config/<package>.php → the profiles array. This is the single source of truth for toolbars, plugins, and per-profile options.x-… tag registration — that is your integration point in forms.First use case
Drop the editor into a CMS or admin form field, persist the HTML, and render it back:
<x-package-editor
name="body"
profile="standard"
:value="old('body', $post->body ?? '')"
/>
$validated = $request->validate(['body' => ['nullable', 'string']]);
$post->update(['body' => $validated['body']]);
Then render on the front end with sanitization (see Gotchas). For this release specifically, the highest-value first test is: open the editor, paste a two-item bulleted list copied from Word, and confirm the saved HTML contains <ul><li>…</li></ul> rather than <p> tags with mso-list styles.
Profile-per-context
Define narrow profiles instead of one mega-toolbar. A minimal profile for comments (bold/italic/link only), standard for CMS body copy, full for marketing pages. This release adds the two format-painter controls to the default standard toolbar — so any profile you haven't customized already gets them, and any profile you copied into config needs a manual merge:
'profiles' => [
'standard' => [
'toolbar' => [
// …existing entries…
'copyStyle',
'pasteStyle',
],
],
],
Treat this as the canonical upgrade chore for v1.3.11: diff your published config against the package's shipped config and port over the two new toolbar entries. Keep a short note in your repo (docs/editor-upgrades.md) recording which toolbar entries you've forked, otherwise every release becomes archaeology.
Word paste as a content-pipeline concern
The Word-list conversion is a parsing change on the paste path, so it only affects newly authored content. Two patterns follow:
mso-list paragraphs. If semantic lists matter for SEO/accessibility, write a one-off command that detects mso-list in the body column and flags rows for manual re-paste — do not attempt a regex rewrite of stored HTML.assertSee('<ul>') / assertDontSee('mso-list') locks in the behavior across future upgrades.Format painter for editorial consistency
The copyStyle/pasteStyle pair lets non-technical editors replicate a heading or callout style without touching source view. The v1.3.11 fix (preserving configured text sizes) means the painter now respects your profile's fontsize/textsize settings instead of collapsing to a default. Practical implication: if your design system sizes text via CSS classes rather than inline styles, the painter may still inject inline font-size — decide now whether inline sizing is acceptable in stored HTML, and configure the profile's size options accordingly rather than cleaning up afterwards.
Livewire / form-object integration
Bind the editor's value with wire:model (or the component's wire:model.defer equivalent) and validate server-side as usual. Because the editor emits HTML on blur/change, add wire:model.debounce.500ms on long documents to avoid a request per keystroke, and keep the sanitizer in the save path, not the render path, if the same HTML is rendered in many places.
Rendering
Store raw HTML, sanitize on write (or on render if you must support legacy rows), and output with {!! !!} inside a wrapper that scopes your prose styles:
<div class="prose">{!! $post->body !!}</div>
--force will eat it. Move customizations into config or a wrapper component before upgrading. Version-control the published asset directory so the diff is visible.copyStyle and pasteStyle must be added by hand to any profile you copied into config/. Profiles left at package defaults get them free. This asymmetry is the most common source of "the buttons are missing" bug reports after this upgrade.mix/vite manifest, or the package's own cache-busting query string). A stale editor bundle plus new toolbar config yields confusing partial failures.<ul>, <ol>, and <li> (and any class attributes you rely on for styling). If you use an allowlist-based purifier, lists pasted from Word will be flattened to text otherwise — which looks like the feature "not working."ul { list-style: none; } in your front-end stylesheet will make semantically correct lists render without bullets. Scope list styling to your prose wrapper.font-size from a Word paste rather than assuming the painter is broken. Comparing before/after HTML in the source view is the fastest debug step.mso-* styles, nested <span>s, empty paragraphs). Consider pairing the editor with a server-side cleanup pass and a stripEmptyTags-style profile option if the package exposes one.v1.3.11, run your editor feature tests, and specifically assert: (a) the two new toolbar items render in the default standard profile, (b) Word-list paste yields <ul>/<ol>, (c) format painter preserves configured sizes. Three assertions cover the entire release surface.How can I help you explore Laravel packages today?