jaikumar0101 / livewire-editor-input
Premium Laravel Livewire WYSIWYG Editor Package with Alpine.js - CKEditor 4, CKEditor 5, and TipTap support
Package info
github.com/Jaikumar0101/laravel-livewire-editor-input
pkg:composer/jaikumar0101/livewire-editor-input
Requires
- php: ^8.1|^8.2|^8.3
- illuminate/support: ^10.0|^11.0|^12.0
- livewire/livewire: ^3.0
Requires (Dev)
- mockery/mockery: ^1.6
- orchestra/testbench: ^8.0|^9.0
- phpunit/phpunit: ^10.0|^11.0
README
A premium, production-ready Laravel package providing powerful WYSIWYG editor components for Livewire 3, powered by Alpine.js. Choose from CKEditor 4, CKEditor 5, or TipTap with extensive customization options.
✨ Features
- 🎨 Three Powerful Editors: CKEditor 4, CKEditor 5, and TipTap
- ⚡ Alpine.js Powered: Reactive, lightweight, and fast
- 🔧 Highly Configurable: Extensive plugin and toolbar customization
- 📦 Easy Installation: Simple setup with sensible defaults
- 🎯 Livewire 3 Native: Built specifically for Livewire 3
- 🌙 Dark Mode Support: Built-in dark theme
- 💾 Auto-Save: Optional auto-save functionality
- 📊 Word/Character Counter: Track content length
- 🎨 Custom Themes: Define your own color schemes
- 🖼️ Image Upload: Configurable image upload support
- 📱 Responsive: Works beautifully on all devices
- 🔒 Read-Only Mode: Toggle edit mode programmatically
- 🎬 Event System: Rich event hooks and listeners
📋 Requirements
- PHP 8.1 or higher
- Laravel 10.x or 11.x
- Livewire 3.x
- Alpine.js 3.x (included via CDN by default)
📦 Installation
Install via Composer:
composer require jaikumar0101/livewire-editor-input
Publish Assets
Publish the package assets:
php artisan vendor:publish --tag=livewire-editor-assets
Publish configuration file (optional):
php artisan vendor:publish --tag=livewire-editor-config
Publish views for customization (optional):
php artisan vendor:publish --tag=livewire-editor-views
Or publish everything at once:
php artisan vendor:publish --tag=livewire-editor
🚀 Quick Start
⚠️ Important: These are Livewire components, not Blade components. Use
<livewire:...>syntax, NOT<x-livewire-editor::...>.
1. Add Assets to Your Layout
🚨 CRITICAL: You MUST add
@livewireEditorAssetsin your layout's<head>section.
<!DOCTYPE html> <html> <head> <!-- Other head content --> {{-- Load CKEditor 5 only --}} @livewireEditorAssets('ckeditor5') {{-- Or load all editors --}} @livewireEditorAssets @livewireStyles </head> <body> {{ $slot }} @livewireScripts </body> </html>
2. Use in Your Livewire Components
In Your View:
<div> <label>Content</label> <livewire:forms.editor.ckeditor5 wire:model="content" /> @error('content') <span class="text-red-500">{{ $message }}</span> @enderror </div>
In Your Livewire Component:
<?php namespace App\Livewire; use Livewire\Component; class PostEditor extends Component { public $content = ''; public function save() { $this->validate([ 'content' => 'required|min:50', ]); Post::create(['body' => $this->content]); session()->flash('message', 'Saved!'); } public function render() { return view('livewire.post-editor'); } }
📝 Available Editors
Usage Note: All editors below are Livewire components. Use
<livewire:...>syntax.
CKEditor 5 (Recommended)
Modern, modular editor with extensive features:
<livewire:forms.editor.ckeditor5 :content="$post->body" :config="['placeholder' => 'Start writing...']" theme="default" />
TipTap
Headless editor with custom toolbar:
<livewire:forms.editor.tiptap :content="$post->body" :showToolbar="true" theme="dark" />
CKEditor 4
Classic, reliable editor:
<livewire:forms.editor.ckeditor :content="$post->body" :height="400" />
💡 Common Usage Examples
Basic Usage (Direct in Blade)
<!-- Simple editor --> <livewire:forms.editor.ckeditor5 wire:model="content" /> <!-- With placeholder and theme --> <livewire:forms.editor.ckeditor5 wire:model="content" :config="['placeholder' => 'Start typing...']" theme="dark" />
In a Form
<form wire:submit="save"> <div> <label for="title">Title</label> <input type="text" wire:model="title" /> </div> <div> <label>Content</label> <livewire:forms.editor.ckeditor5 wire:model="content" /> @error('content') <span class="text-red-500">{{ $message }}</span> @enderror </div> <button type="submit">Save</button> </form>
Multiple Editors on Same Page
<div> <h3>Introduction</h3> <livewire:forms.editor.ckeditor5 wire:model="introduction" key="intro-editor" /> </div> <div> <h3>Main Content</h3> <livewire:forms.editor.ckeditor5 wire:model="content" key="main-editor" /> </div> <div> <h3>Conclusion</h3> <livewire:forms.editor.tiptap-editor wire:model="conclusion" key="conclusion-editor" /> </div>
With Initial Content
<!-- In your Livewire component --> <livewire:forms.editor.ckeditor5 :content="$post->body" wire:model="body" />
Read-Only Mode
<!-- In your Livewire component --> <livewire:forms.editor.ckeditor5 :content="$post->body" :readOnly="true" />
⚙️ Configuration
The configuration file offers extensive customization options:
// config/livewire-editor.php return [ // Default editor 'default' => 'ckeditor5', // Asset loading strategy: 'cdn', 'local', 'vite', 'mix' 'asset_strategy' => 'cdn', // Editor-specific configurations 'ckeditor5' => [ 'toolbar' => [...], 'plugins' => [...], 'image_upload' => [...], // ... more options ], 'tiptap' => [ 'extensions' => [...], 'toolbar' => [...], 'bubble_menu' => [...], // ... more options ], // Global settings 'global' => [ 'auto_save' => [ 'enabled' => true, 'interval' => 30000, // ms ], 'counter' => [ 'enabled' => true, 'type' => 'words', // 'words' or 'characters' ], ], // Custom themes 'themes' => [ 'default' => [...], 'dark' => [...], ], ];
🎨 Advanced Usage
Custom Configuration
@php $editorConfig = [ 'toolbar' => [ 'items' => ['heading', 'bold', 'italic', 'link', 'bulletedList'], ], 'placeholder' => 'Write something amazing...', 'heading' => [ 'options' => [ ['model' => 'paragraph', 'title' => 'Paragraph'], ['model' => 'heading1', 'view' => 'h1', 'title' => 'Heading 1'], ['model' => 'heading2', 'view' => 'h2', 'title' => 'Heading 2'], ] ] ]; @endphp <livewire:forms.editor.ckeditor5 :content="$content" :config="$editorConfig" />
Programmatic Control
// In your Livewire component public function clearEditor() { $this->dispatch('clear-editor-content', [ 'editorId' => $this->editorId ]); } public function setReadOnly() { $this->dispatch('set-editor-readonly', [ 'editorId' => $this->editorId, 'readOnly' => true ]); }
Event Listeners
<div> <livewire:forms.editor.ckeditor5 wire:model="content" /> @push('scripts') <script> Livewire.on('editor-updated', (data) => { console.log('Content updated:', data.content); }); Livewire.on('editor-auto-save', (data) => { // Handle auto-save console.log('Auto-saving...', data.content); }); </script> @endpush </div>
Multiple Editors
<div class="space-y-6"> <div> <label>Introduction</label> <livewire:forms.editor.ckeditor5 wire:model="introduction" key="intro-editor" /> </div> <div> <label>Main Content</label> <livewire:forms.editor.ckeditor5 wire:model="content" key="main-editor" /> </div> </div>
Image Upload Configuration
CKEditor 5:
// config/livewire-editor.php 'ckeditor5' => [ 'simpleUpload' => [ 'uploadUrl' => '/api/editor/upload', 'withCredentials' => true, 'headers' => [ 'X-CSRF-TOKEN' => 'CSRF-Token', ], ], ],
Laravel Route:
Route::post('/api/editor/upload', function (Request $request) { $request->validate([ 'upload' => 'required|image|max:2048', ]); $path = $request->file('upload')->store('uploads', 'public'); $url = Storage::url($path); return response()->json([ 'url' => $url ]); })->middleware('auth');
Custom Plugins (CKEditor 5)
'ckeditor5' => [ 'plugins' => [ 'Essentials', 'Bold', 'Italic', // Add your custom plugins here 'MyCustomPlugin', ], ],
TipTap Extensions
'tiptap' => [ 'extensions' => [ 'StarterKit' => [ 'enabled' => true, 'config' => [ 'heading' => [ 'levels' => [1, 2, 3], ], ], ], 'Underline' => ['enabled' => true], 'Link' => [ 'enabled' => true, 'config' => [ 'openOnClick' => false, ], ], 'Image' => [ 'enabled' => true, 'config' => [ 'inline' => true, 'allowBase64' => true, ], ], ], ],
Custom Toolbar (TipTap)
'tiptap' => [ 'toolbar' => [ 'enabled' => true, 'sticky' => true, 'buttons' => [ ['type' => 'bold', 'icon' => 'B', 'title' => 'Bold'], ['type' => 'italic', 'icon' => 'I', 'title' => 'Italic'], ['type' => 'separator'], ['type' => 'heading', 'level' => 1, 'icon' => 'H1', 'title' => 'Heading 1'], ['type' => 'link', 'icon' => '🔗', 'title' => 'Link'], ], ], ],
🎨 Theming
Define custom themes:
'themes' => [ 'custom' => [ 'primary_color' => '#8b5cf6', 'toolbar_bg' => '#f3f4f6', 'editor_bg' => '#ffffff', 'border_color' => '#d1d5db', 'text_color' => '#111827', ], ],
Use in component:
<livewire:forms.editor.ckeditor5 :content="$content" theme="custom" />
📊 Features in Detail
Auto-Save
// Enable globally 'global' => [ 'auto_save' => [ 'enabled' => true, 'interval' => 30000, // Save every 30 seconds ], ],
Listen for auto-save events:
@push('scripts') <script> Livewire.on('editor-auto-save', (data) => { // Send AJAX request to save fetch('/api/auto-save', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content }, body: JSON.stringify({ content: data.content }) }); }); </script> @endpush
Word/Character Counter
'global' => [ 'counter' => [ 'enabled' => true, 'type' => 'words', // or 'characters' ], ],
Read-Only Mode
// In Livewire component public $readOnly = false; public function toggleReadOnly() { $this->readOnly = !$this->readOnly; }
🔧 Troubleshooting
❌ Error: "Undefined variable $editorId"
Problem: You're using Blade component syntax instead of Livewire component syntax.
<!-- ❌ WRONG - This will cause errors --> <x-livewire-editor::forms.editor.ckeditor5 /> <!-- ✅ CORRECT - Use this instead --> <livewire:forms.editor.ckeditor5 />
Why: These are Livewire components, not Blade components. Always use <livewire:...> syntax.
❌ Error: "Alpine Expression Error: ckeditorComponent is not defined"
Problem: Missing @livewireEditorAssets in your layout.
Solution: Add the assets directive to your layout's <head>:
<head> @livewireEditorAssets('ckeditor') <!-- In head --> @livewireStyles </head> <body> @livewireScripts </body>
Additional Checks:
- Clear browser cache
- Check browser console for script loading errors
- Verify Alpine.js is loading (check Network tab)
❌ Views Published and Out of Date
Problem: Getting errors after updating the package.
Solution: Delete published views to use package views:
rm -rf resources/views/vendor/livewire-editor
Or re-publish with --force:
php artisan vendor:publish --tag=livewire-editor-views --force
Why: Published views in your project override package views. Updates don't affect published files.
Editors Not Loading
- Ensure
@livewireEditorAssetsis in your<head> - Check browser console for errors
- Verify CDN access
- Clear browser cache
Content Not Syncing
- Use
wire:modelfor two-way binding - Ensure Livewire is properly initialized
- Check for JavaScript errors
Alpine.js Conflicts
If you already have Alpine.js loaded, use:
@livewireEditorJs('ckeditor5') @livewireEditorCss
📚 Documentation
🤝 Contributing
Contributions are welcome! Please see CONTRIBUTING.md for details.
🐛 Issues
Found a bug? Please open an issue.
📄 License
This package is open-sourced software licensed under the MIT license.
🙏 Credits
- CKEditor 4 by CKSource
- CKEditor 5 by CKSource
- TipTap by Tiptap GmbH
- Alpine.js by Caleb Porzio
- Livewire by Caleb Porzio
🌟 Support
If you find this package helpful, please ⭐ star it on GitHub!
Made with ❤️ for the Laravel community