jaikumar0101/livewire-editor-input

Premium Laravel Livewire WYSIWYG Editor Package with Alpine.js - CKEditor 4, CKEditor 5, and TipTap support

Maintainers

Package info

github.com/Jaikumar0101/laravel-livewire-editor-input

pkg:composer/jaikumar0101/livewire-editor-input

Statistics

Installs: 7

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 0

v1.0.7 2026-02-15 05:56 UTC

This package is auto-updated.

Last update: 2026-03-15 06:10:02 UTC


README

Latest Version License

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 @livewireEditorAssets in 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:

  1. Clear browser cache
  2. Check browser console for script loading errors
  3. 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

  1. Ensure @livewireEditorAssets is in your <head>
  2. Check browser console for errors
  3. Verify CDN access
  4. Clear browser cache

Content Not Syncing

  1. Use wire:model for two-way binding
  2. Ensure Livewire is properly initialized
  3. 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

🌟 Support

If you find this package helpful, please ⭐ star it on GitHub!

Made with ❤️ for the Laravel community