Weave 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

Ux Editor Laravel Package

pentiminax/ux-editor

pentiminax/ux-editor bundles a ready-to-use rich-text/WYSIWYG editor with PHP form integration, letting you add a configurable editor field to your forms, manage its assets, and customize toolbars with minimal setup.

View on GitHub
Deep Wiki
Context7

Getting Started

pentiminax/ux-editor is a pre-1.0 rich-text/editor Blade component for Laravel. Treat it as early-adopter territory: pin the exact version and read the changelog on every bump.

Install

composer require pentiminax/ux-editor

Then publish whatever the service provider exposes — check vendor/pentiminax/ux-editor/src/UxEditorServiceProvider.php for the actual tag names (typically ux-editor-config, ux-editor-views, and possibly ux-editor-assets):

php artisan vendor:publish --provider="Pentiminax\UxEditor\UxEditorServiceProvider"

If the package ships uncompiled JS/CSS, install and build the front-end dependencies before first render.

Where to look first

  1. README.md — component tag name, supported attributes, and the JS stack the editor is built on.
  2. config/ux-editor.php (after publishing) — toolbar config, asset loading strategy, default options.
  3. The Blade component class in src/View/Components/ — this is the source of truth for which attributes are forwarded versus consumed.
  4. The JS entrypoint in resources/js/ — decides how the editor initialises and how it targets the DOM.

First use case

Drop-in replacement for a <textarea> in an admin CRUD form:

<form method="POST" action="{{ route('posts.store') }}">
    @csrf
    <x-ux-editor name="body" :value="old('body', $post->body ?? '')" id="post-body" />
    <button type="submit">Save</button>
</form>

Read it back on the server with $request->input('body') — you get HTML, not markdown. Persist as-is (in a text/longText column) and sanitise on output.

Implementation Patterns

Always pass an explicit id. As of v0.1.2 the package no longer generates one for you (see Gotchas). For multiple editors on a page this is non-negotiable:

<x-ux-editor name="summary" id="editor-summary" />
<x-ux-editor name="body"    id="editor-body" />

Binding to a model field. Pass the persisted HTML through :value (escaped by Blade). Avoid using the component as an unescaped {!! !!} sink.

Livewire. If the component bridges to Livewire, the usual pattern is a wrapper with wire:ignore around the editor so Livewire's DOM morphing doesn't tear down the contenteditable node, plus a manual sync into the property:

<div wire:ignore>
    <x-ux-editor name="body" id="livewire-body" :value="$body" />
</div>

Attach a listener to the editor's change event and $wire.set('body', html), or place a hidden input inside the wire:ignore block so Livewire picks it up on submit. Confirm in the source which event name the package dispatches before wiring this.

Multiple editor instances / custom toolbars. Two viable approaches: (a) publish the config and define named presets, then reference them per-instance; (b) publish the views and override the component partial for one-off layouts. Config presets scale better; view overrides are the escape hatch when you need markup the package doesn't expose.

Sanitisation pipeline. Store the raw HTML, sanitise on render — allowlist-based (mews/purifier, or strip_tags with an explicit tag list) rather than a denylist. If you sanitise on input instead, you'll destroy content the user can still see in the editor and create confusing round-trip bugs.

Form objects / validation. Validate the HTML like any other string: required, max:65535. Content-length on HTML is a poor proxy for visible length, so if you enforce limits, strip tags first.

Testing. Editor output is client-side, so feature tests should assert the component renders with the attributes you passed (assertSee('id="post-body"', false)) and that the controller persists submitted HTML. Don't try to drive the contenteditable in a Pest/PHPUnit test — cover the JS separately or skip it.

Gotchas and Tips

v0.1.2 is a breaking change under a patch number. "Remove id generation" means any of these will silently break:

  • CSS/JS targeting a generated id (e.g. #editor, #ux-editor-1).
  • <label for="..."> pairs — the for no longer matches anything.
  • Scripts that queried the first editor by id to call an API method.
  • Pages with multiple editors that relied on auto-uniqueness — ids may now collide or be absent entirely.

If you can't migrate immediately, pin "pentiminax/ux-editor": "0.1.1". Since the removal shipped as 0.1.2 rather than 0.2.0, do not use ^0.1 in composer.json; pin exact versions and review diffs on every release.

Assets not loading is the most common first-run failure. Symptoms: a bare <textarea> or an empty div, and a console error about an undefined constructor. Check (1) whether the package publishes compiled assets or expects a Vite build, (2) whether your vite.config.js includes the package's entry, (3) whether you ran the publish step at all. php artisan vendor:publish is idempotent-ish but won't overwrite without --force, so stale published views after an upgrade are a real trap — re-publish views when the component markup changes.

Livewire re-renders wipe the editor. Any morph that replaces the editor's container leaves you with a dead contenteditable. wire:ignore on the wrapper is the standard fix; also re-initialise on livewire:navigated if you use SPA-style navigation.

Debugging tip: inspect the rendered DOM. The component should emit data-* attributes or a specific class the JS controller keys off. If those are present but the editor isn't, the problem is assets/JS; if they're absent, the problem is the Blade component or your attributes being swallowed.

Attribute passthrough is inconsistent in early releases. Some attributes are consumed by the component, others are dumped onto the root element. When an option "doesn't work", check whether it belongs in the component tag or in the published config — the two are frequently not interchangeable.

Extension points, in order of durability: published config → published views → a thin Blade wrapper of your own → subclassing the component. Prefer wrapping over subclassing; the public API is not yet stable and a subclass will break on minor bumps.

Upgrade discipline. Diff src/ between tags before upgrading, not just the release notes — the 0.1.2 note is one line and doesn't describe migration. Run your form tests and manually click through one editor per preset after each bump; the failure mode here is visual and silent.

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.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console