| Install | |
|---|---|
composer require jaikumar0101/livewire-editor-input |
|
| Latest Version: | v1.0.7 |
| PHP: | ^8.1|^8.2|^8.3 |
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.
Install via Composer:
composer require jaikumar0101/livewire-editor-input
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
⚠️ Important: These are Livewire components, not Blade components. Use
<livewire:...>syntax, NOT<x-livewire-editor::...>.
🚨 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>
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');
}
}
Usage Note: All editors below are Livewire components. Use
<livewire:...>syntax.
Modern, modular editor with extensive features:
<livewire:forms.editor.ckeditor5
:content="$post->body"
:config="['placeholder' => 'Start writing...']"
theme="default"
/>
Headless editor with custom toolbar:
<livewire:forms.editor.tiptap
:content="$post->body"
:showToolbar="true"
theme="dark"
/>
Classic, reliable editor:
<livewire:forms.editor.ckeditor
:content="$post->body"
:height="400"
/>
<!-- 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"
/>
<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>
<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>
<!-- In your Livewire component -->
<livewire:forms.editor.ckeditor5
:content="$post->body"
wire:model="body"
/>
<!-- In your Livewire component -->
<livewire:forms.editor.ckeditor5
:content="$post->body"
:readOnly="true"
/>
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' => [...],
],
];
@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"
/>
// 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
]);
}
<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>
<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>
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');
'ckeditor5' => [
'plugins' => [
'Essentials',
'Bold',
'Italic',
// Add your custom plugins here
'MyCustomPlugin',
],
],
'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,
],
],
],
],
'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'],
],
],
],
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"
/>
// 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
'global' => [
'counter' => [
'enabled' => true,
'type' => 'words', // or 'characters'
],
],
// In Livewire component
public $readOnly = false;
public function toggleReadOnly()
{
$this->readOnly = !$this->readOnly;
}
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.
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:
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.
@livewireEditorAssets is in your <head>wire:model for two-way bindingIf you already have Alpine.js loaded, use:
@livewireEditorJs('ckeditor5')
@livewireEditorCss
Contributions are welcome! Please see CONTRIBUTING.md for details.
Found a bug? Please open an issue.
This package is open-sourced software licensed under the MIT license.
If you find this package helpful, please ⭐ star it on GitHub!
Made with ❤️ for the Laravel community