{"id":30134599,"url":"https://github.com/mati365/ckeditor5-livewire","last_synced_at":"2026-02-11T19:35:17.084Z","repository":{"id":311113901,"uuid":"1027039957","full_name":"Mati365/ckeditor5-livewire","owner":"Mati365","description":"📝 CKEditor 5 for Livewire - easy WYSIWYG editor for your Laravel apps! ⚡ Works great with Livewire components or regular Blade forms. 💡 Simple setup, supports custom builds, dynamic loading, and localization. 🔧 Includes JS hooks, reusable components, and full customization. 🎯 Perfect for both open-source and commercial projects!","archived":false,"fork":false,"pushed_at":"2026-01-21T20:14:08.000Z","size":1435,"stargazers_count":36,"open_issues_count":0,"forks_count":4,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-01-22T08:59:48.651Z","etag":null,"topics":["ckeditor","form","laravel","livewire","rich-text-editor","web-editor","wysiwyg"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Mati365.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-07-27T07:15:28.000Z","updated_at":"2026-01-21T20:14:13.000Z","dependencies_parsed_at":"2025-10-15T20:25:26.185Z","dependency_job_id":null,"html_url":"https://github.com/Mati365/ckeditor5-livewire","commit_stats":null,"previous_names":["mati365/ckeditor5-livewire"],"tags_count":15,"template":false,"template_full_name":null,"purl":"pkg:github/Mati365/ckeditor5-livewire","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mati365%2Fckeditor5-livewire","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mati365%2Fckeditor5-livewire/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mati365%2Fckeditor5-livewire/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mati365%2Fckeditor5-livewire/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Mati365","download_url":"https://codeload.github.com/Mati365/ckeditor5-livewire/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mati365%2Fckeditor5-livewire/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29342124,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-11T18:58:20.535Z","status":"ssl_error","status_checked_at":"2026-02-11T18:56:44.814Z","response_time":97,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ckeditor","form","laravel","livewire","rich-text-editor","web-editor","wysiwyg"],"created_at":"2025-08-10T21:17:38.672Z","updated_at":"2026-02-11T19:35:17.076Z","avatar_url":"https://github.com/Mati365.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ckeditor5-livewire\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square)](LICENSE)\n[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-green.svg?style=flat-square)](http://makeapullrequest.com)\n![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/mati365/ckeditor5-livewire?style=flat-square)\n[![GitHub issues](https://img.shields.io/github/issues/mati365/ckeditor5-livewire?style=flat-square)](https://github.com/Mati365/ckeditor5-livewire/issues)\n[![TS Coverage](https://img.shields.io/badge/TypeScript-100%25-brightgreen?logo=typescript\u0026logoColor=white\u0026style=flat-square)](https://app.codecov.io/gh/Mati365/ckeditor5-livewire/tree/main/npm_package%2Fsrc)\n[![PHP Coverage](https://img.shields.io/badge/PHP-100%25-brightgreen?logo=php\u0026logoColor=white\u0026style=flat-square)](https://app.codecov.io/gh/Mati365/ckeditor5-livewire/tree/main/src)\n![NPM Version](https://img.shields.io/npm/v/ckeditor5-livewire?style=flat-square)\n![Packagist Version](https://img.shields.io/packagist/v/mati365/ckeditor5-livewire?style=flat-square\u0026color=%239245ba)\n\nCKEditor 5 for Livewire — a lightweight WYSIWYG editor integration for Laravel. It works with Livewire components and standard Blade forms. Easy to set up, it supports custom builds, dynamic loading, and localization. The package includes JavaScript hooks, reusable components, and options for customization, and is suitable for both open-source and commercial projects.\n\n\u003e [!IMPORTANT]\n\u003e This integration is unofficial and not maintained by CKSource. For official CKEditor 5 documentation, visit [ckeditor.com](https://ckeditor.com/docs/ckeditor5/latest/). If you encounter any issues in editor, please report them on the [GitHub repository](https://github.com/ckeditor/ckeditor5/issues).\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/intro-classic-editor.png\" alt=\"CKEditor 5 Classic Editor in Laravel Livewire application\"\u003e\n\u003c/p\u003e\n\n## Table of Contents\n\n- [ckeditor5-livewire](#ckeditor5-livewire)\n  - [Table of Contents](#table-of-contents)\n  - [Installation 🚀](#installation-)\n    - [🏠 Self-hosted via NPM](#-self-hosted-via-npm)\n    - [📡 CDN Distribution](#-cdn-distribution)\n  - [Basic Usage 🏁](#basic-usage-)\n    - [Simple Editor ✏️](#simple-editor-️)\n  - [Configuration ⚙️](#configuration-️)\n    - [Override default preset configuration 🧑‍💻](#override-default-preset-configuration-)\n    - [Define your configuration directly in the view 💻](#define-your-configuration-directly-in-the-view-)\n    - [Define reusable configuration presets 🧩](#define-reusable-configuration-presets-)\n    - [Dynamic presets 🎯](#dynamic-presets-)\n  - [Providing the License Key 🗝️](#providing-the-license-key-️)\n  - [Localization 🌍](#localization-)\n    - [CDN Translation Loading 🌐](#cdn-translation-loading-)\n    - [Global Translation Config 🛠️](#global-translation-config-️)\n    - [Custom translations 🌐](#custom-translations-)\n  - [Editor Types 🖊️](#editor-types-️)\n    - [Classic editor 📝](#classic-editor-)\n    - [Inline editor 📝](#inline-editor-)\n    - [Decoupled editor 🌐](#decoupled-editor-)\n    - [Multiroot editor 🌳](#multiroot-editor-)\n  - [Advanced configuration ⚙️](#advanced-configuration-️)\n    - [Livewire Sync 🔄](#livewire-sync-)\n      - [Two way binding using `wire:model` ⛓️](#two-way-binding-using-wiremodel-️)\n      - [Bidirectional Communication using Events 🔄](#bidirectional-communication-using-events-)\n        - [Editor → Livewire: Content Change Event 📤](#editor--livewire-content-change-event-)\n        - [Livewire → Editor: Set Content Event 📥](#livewire--editor-set-content-event-)\n    - [Focus Tracking 👁️](#focus-tracking-️)\n    - [Watchdog 🐶](#watchdog-)\n      - [How it works ⚙️](#how-it-works-️)\n      - [Disabling the watchdog 🚫](#disabling-the-watchdog-)\n  - [Context 🤝](#context-)\n    - [Basic usage 🔧](#basic-usage--1)\n    - [Custom context translations 🌐](#custom-context-translations-)\n  - [Custom plugins 🧩](#custom-plugins-)\n  - [Development ⚙️](#development-️)\n    - [Running Tests 🧪](#running-tests-)\n  - [Psst... 👀](#psst-)\n  - [Trademarks 📜](#trademarks-)\n  - [License 📜](#license-)\n\n## Installation 🚀\n\nChoose between two installation methods based on your needs. Both approaches provide the same functionality but differ in how CKEditor 5 assets are loaded and managed.\n\n### 🏠 Self-hosted via NPM\n\nBundle CKEditor 5 with your application for full control over assets, custom builds, and offline support. This method is recommended for advanced users or production applications with specific requirements.\n\n**Complete setup:**\n\n1. **Add PHP dependency** to your `composer.json`:\n\n   ```bash\n   composer require mati365/ckeditor5-livewire\n   ```\n\n2. **Install CKEditor 5 via NPM:**\n\n   ```bash\n   npm install ckeditor5 ckeditor5-premium-features ckeditor5-livewire\n   ```\n\n   **Note:** If you use `esbuild` as your bundler, the `ckeditor5-premium-features` may be not required. However, it is needed for `vite` as it has stricter verification of dependencies. Even if you don't use any premium features, the package depends on it and you can safely install it on free or open-source licenses.\n\n3. **Import integration** in your `resources/js/app.js`:\n\n   ```javascript\n   import 'ckeditor5-livewire';\n   ```\n\n4. **Import styles** in your `resources/css/app.css`:\n\n   ```css\n   @import \"ckeditor5/ckeditor5.css\";\n   ```\n\n5. **Use in Blade templates** (no CDN assets needed):\n\n   ```blade\n   \u003clivewire:ckeditor5 content=\"\u003cp\u003eHello world!\u003c/p\u003e\" /\u003e\n   ```\n\n### 📡 CDN Distribution\n\nLoad CKEditor 5 directly from CKSource's CDN - no build configuration required. This method is ideal for most users who want quick setup and don't need custom builds.\n\n**Complete setup:**\n\n1. **Add PHP dependency** to your `composer.json`:\n\n   ```bash\n   composer require mati365/ckeditor5-livewire\n   ```\n\n2. **Install NPM package:**\n\n   ```bash\n   npm install ckeditor5-livewire\n   ```\n\n3. **Import integration** in your `resources/js/app.js`:\n\n   ```javascript\n   import 'ckeditor5-livewire';\n   ```\n\n4. **Exclude CKEditor from bundler** in your `vite.config.js`:\n\n   ```javascript\n   import { viteCKEditorExternalize } from 'ckeditor5-livewire/bundler/vite-ckeditor5-externalize';\n   import laravel from 'laravel-vite-plugin';\n   import { defineConfig } from 'vite';\n\n   export default defineConfig({\n     plugins: [\n       laravel({\n         input: ['resources/css/app.css', 'resources/js/app.js'],\n         refresh: true,\n       }),\n       viteCKEditorExternalize()\n     ],\n   });\n   ```\n\n5. **Add license key** (see [Providing the License Key 🗝️](#providing-the-license-key-️) section)\n\n6. **Use in Blade templates:**\n\n   ```blade\n   \u003c!-- Load CDN assets in \u003chead\u003e (based on `default` preset) --\u003e\n   \u003cx-ckeditor5-assets /\u003e\n\n   \u003c!-- or with specific features (overrides `default` preset) --\u003e\n   \u003cx-ckeditor5-assets\n       preset=\"default\"\n       editorVersion=\"43.0.0\"\n       :translations=\"['pl', 'de']\"\n       ckboxVersion=\"2.6.0\"\n       ckboxTheme=\"lark\"\n       nonce=\"csp-nonce\"\n       premium\n   /\u003e\n\n   \u003c!-- Use editor anywhere in \u003cbody\u003e --\u003e\n   \u003clivewire:ckeditor5 content=\"\u003cp\u003eHello world!\u003c/p\u003e\" /\u003e\n   ```\n\nThat's it! 🎉\n\n## Basic Usage 🏁\n\nGet started with the most common usage patterns. These examples show how to render editors in your templates and handle real-time content changes.\n\n### Simple Editor ✏️\n\nCreate a basic editor with default toolbar and features. Perfect for simple content editing without server synchronization.\n\n```blade\n\u003c!-- CDN only: Load assets in \u003chead\u003e --\u003e\n\u003cx-ckeditor5-assets /\u003e\n\n\u003c!-- Render editor with initial content --\u003e\n\u003clivewire:ckeditor5\n    content=\"\u003cp\u003eInitial content\u003c/p\u003e\"\n    editableHeight=\"300px\"\n/\u003e\n\n\u003c!-- You can also use Livewire model binding for real-time sync --\u003e\n\u003clivewire:ckeditor5 wire:model.live=\"content\" /\u003e\n```\n\n## Configuration ⚙️\n\nYou can configure the editor _presets_ in your `config/ckeditor5.php` file. The default preset is `default`, which provides a basic configuration with a toolbar and essential plugins. The preset is an array that contains the editor configuration, including the toolbar items and plugins. There can be multiple presets, and you can switch between them by passing the `preset` attribute to the component.\n\n### Override default preset configuration 🧑‍💻\n\nYou can pass initial content and merge additional configuration. In scenario below, the `mergeConfig` will extend the `default` preset configuration to make the menu bar visible. It's only shallow merge, so nested arrays will be replaced, not merged.\n\n```blade\n\u003clivewire:ckeditor5\n    content='\u003cp\u003eThis is the initial content of the editor.\u003c/p\u003e'\n    :mergeConfig=\"[\n        'menuBar' =\u003e [\n            'isVisible' =\u003e true\n        ]\n    ]\"\n/\u003e\n```\n\n### Define your configuration directly in the view 💻\n\nOverride the default configuration with custom plugins and toolbar items. In this example, the editor will only have `Essentials`, `Paragraph`, `Bold`, `Italic`, `Link`, and `Undo` plugins, and the toolbar will contain only bold, italic, link, undo, and redo buttons. The editor locale is set to Polish (`pl`), and a custom translation for the \"Bold\" label is provided.\n\n```blade\n\u003clivewire:ckeditor5\n    locale=\"pl\"\n    content=\"\u003cp\u003eThis editor has a custom configuration.\u003c/p\u003e\"\n    :customTranslations=\"[\n        'pl' =\u003e [\n            'Bold' =\u003e 'Grubo'\n        ]\n    ]\"\n    :config=\"[\n        'plugins' =\u003e [\n            'Essentials',\n            'Paragraph',\n            'Bold',\n            'Italic',\n            'Link',\n            'Undo'\n        ],\n        'toolbar' =\u003e [\n            'items' =\u003e [\n                'bold',\n                'italic',\n                'link',\n                'undo',\n                'redo'\n            ]\n        ]\n    ]\"\n/\u003e\n```\n\n### Define reusable configuration presets 🧩\n\nIn order to override the default preset or add custom presets, publish the configuration file:\n\n```bash\nphp artisan vendor:publish --tag=ckeditor5-config\n```\n\nThen modify `config/ckeditor5.php`:\n\n```php\n\u003c?php\n\nreturn [\n    'presets' =\u003e [\n        'minimal' =\u003e [\n            'cloud' =\u003e [\n                'editorVersion' =\u003e '47.0.0',\n                'premium' =\u003e true,\n                'translations' =\u003e ['pl'],\n                'ckbox' =\u003e [\n                    'version' =\u003e '1.0.0'\n                ]\n            ],\n            'config' =\u003e [\n                'toolbar' =\u003e [\n                    'items' =\u003e ['bold', 'italic', 'link']\n                ],\n                'plugins' =\u003e [\n                    'Bold',\n                    'Italic',\n                    'Link',\n                    'Essentials',\n                    'Paragraph'\n                ]\n            ]\n        ],\n        'full' =\u003e [\n            'config' =\u003e [\n                'toolbar' =\u003e [\n                    'items' =\u003e [\n                        'heading',\n                        '|',\n                        'bold',\n                        'italic',\n                        'underline',\n                        '|',\n                        'link',\n                        'insertImage',\n                        'insertTable',\n                        '|',\n                        'bulletedList',\n                        'numberedList',\n                        'blockQuote'\n                    ]\n                ],\n                'plugins' =\u003e [\n                    'Heading',\n                    'Bold',\n                    'Italic',\n                    'Underline',\n                    'Link',\n                    'ImageBlock',\n                    'ImageUpload',\n                    'Table',\n                    'List',\n                    'BlockQuote',\n                    'Essentials',\n                    'Paragraph'\n                ]\n            ]\n        ]\n    ]\n];\n```\n\nYou can use these presets by passing the `preset` attribute to the `\u003clivewire:ckeditor5\u003e` component.\n\n```blade\n\u003clivewire:ckeditor5 preset=\"minimal\" content=\"\u003cp\u003eSimple editor\u003c/p\u003e\" /\u003e\n```\n\n### Dynamic presets 🎯\n\nYou can also create dynamic presets that can be modified at runtime. This is useful if you want to change the editor configuration based on user input or other conditions.\n\n```php\nuse CKEditor5\\Livewire\\Preset\\PresetParser;\n\nclass Editor extends Component\n{\n    public array $preset;\n\n    public function mount()\n    {\n        $this-\u003epreset = PresetParser::parse([\n            'config' =\u003e [\n                'toolbar' =\u003e [\n                    'items' =\u003e ['bold', 'italic', 'link']\n                ],\n                'plugins' =\u003e [\n                    'Bold',\n                    'Italic',\n                    'Link',\n                    'Essentials',\n                    'Paragraph'\n                ]\n            ]\n        ]);\n    }\n}\n```\n\nYou can then pass the dynamic preset to the component:\n\n```blade\n\u003clivewire:ckeditor5 :preset=\"$preset\" /\u003e\n```\n\n## Providing the License Key 🗝️\n\nCKEditor 5 requires a license key when using the official CDN or premium features. You can provide the license key in two simple ways:\n\n1. **Environment variable**: Set the `CKEDITOR5_LICENSE_KEY` environment variable in your `.env` file:\n\n   ```env\n   CKEDITOR5_LICENSE_KEY=your-license-key-here\n   ```\n\n2. **Preset config**: You can also set the license key directly in your preset configuration in `config/ckeditor5.php`:\n\n   ```php\n   'presets' =\u003e [\n       'default' =\u003e [\n           'licenseKey' =\u003e 'your-license-key-here'\n       ]\n   ]\n   ```\n\nIf you use CKEditor 5 under the GPL license, you do not need to provide a license key. However, if you choose to set one, it must be set to `GPL`.\n\nIf both are set, the preset config takes priority. For more details, see the [CKEditor 5 licensing guide](https://ckeditor.com/docs/ckeditor5/latest/getting-started/licensing/license-and-legal.html).\n\n## Localization 🌍\n\nSupport multiple languages in the editor UI and content. Learn how to load translations via CDN or configure them globally.\n\n### CDN Translation Loading 🌐\n\nDepending on your setup, you can preload translations via CDN or let your bundler handle them automatically using lazy imports.\n\n```blade\n\u003c!-- CDN only: Load specific translations --\u003e\n\u003cx-ckeditor5-assets :translations=\"['pl', 'de', 'fr']\" /\u003e\n\n\u003clivewire:ckeditor5\n    locale=\"pl\"\n    content=\"\u003cp\u003eContent with Polish UI\u003c/p\u003e\"\n/\u003e\n```\n\n### Global Translation Config 🛠️\n\nYou can also configure translations globally in your `config/ckeditor5.php` file. This is useful if you want to load translations for multiple languages at once or set a default language for the editor. Keep in mind that this configuration is only used when loading translations via CDN. If you are using self-hosted setup, translations are handled by your bundler automatically.\n\n```php\n// config/ckeditor5.php\nreturn [\n    'presets' =\u003e [\n        'default' =\u003e [\n            'cloud' =\u003e [\n                'translations' =\u003e ['pl', 'de', 'fr']  // CDN only\n            ]\n        ]\n    ]\n];\n```\n\n**Note:** For self-hosted setups, translations are handled by your bundler automatically.\n\n### Custom translations 🌐\n\nYou can also provide custom translations for the editor. This is useful if you want to override existing translations or add new ones. Custom translations can be provided in the preset configuration.\n\n```php\n// config/ckeditor5.php\nreturn [\n    'presets' =\u003e [\n        'default' =\u003e [\n            'customTranslations' =\u003e [\n                'en' =\u003e [\n                    'Bold' =\u003e 'Custom Bold',\n                    'Italic' =\u003e 'Custom Italic'\n                ],\n                'pl' =\u003e [\n                    'Bold' =\u003e 'Grubo',\n                    'Italic' =\u003e 'Kursywa'\n                ]\n            ]\n        ]\n    ]\n];\n```\n\n## Editor Types 🖊️\n\nCKEditor 5 for Livewire supports multiple distinct editor types, each designed for specific use cases. Choose the one that best fits your application's layout and functionality requirements.\n\n### Classic editor 📝\n\nTraditional WYSIWYG editor with a fixed toolbar above the editing area. Best for standard content editing scenarios like blog posts, articles, or forms.\n\n![CKEditor 5 Classic Editor in Livewire application](docs/classic.png)\n\n```blade\n\u003c!-- CDN assets in \u003chead\u003e --\u003e\n\u003cx-ckeditor5-assets /\u003e\n\n\u003c!-- Classic editor in \u003cbody\u003e --\u003e\n\u003clivewire:ckeditor5\n    editorType=\"classic\"\n    content=\"\u003cp\u003eInitial content here\u003c/p\u003e\"\n    editableHeight=\"300px\"\n/\u003e\n```\n\n### Inline editor 📝\n\nMinimalist editor that appears directly within content when clicked. Ideal for in-place editing scenarios where the editing interface should be invisible until needed.\n\n![CKEditor 5 Inline Editor in Livewire application](docs/inline-editor.png)\n\n```blade\n\u003c!-- CDN assets in \u003chead\u003e --\u003e\n\u003cx-ckeditor5-assets /\u003e\n\n\u003c!-- Inline editor --\u003e\n\u003clivewire:ckeditor5\n    editorType=\"inline\"\n    content=\"\u003cp\u003eClick here to edit this content\u003c/p\u003e\"\n    editableHeight=\"300px\"\n/\u003e\n```\n\n**Note:** Inline editors don't work with `\u003ctextarea\u003e` elements and may not be suitable for traditional form scenarios.\n\n### Decoupled editor 🌐\n\nFlexible editor where toolbar and editing area are completely separated. Provides maximum layout control for custom interfaces and complex applications.\n\n![CKEditor 5 Decoupled Editor in Livewire application](docs/decoupled-editor.png)\n\n```blade\n\u003c!-- CDN assets in \u003chead\u003e --\u003e\n\u003cx-ckeditor5-assets /\u003e\n\n\u003c!-- Editor instance --\u003e\n\u003clivewire:ckeditor5\n    editorId=\"decoupled-editor\"\n    editorType=\"decoupled\"\n    :content=\"['main' =\u003e '\u003cp\u003eThis is the initial content of the decoupled editor.\u003c/p\u003e']\"\n/\u003e\n\n\u003c!-- Separate toolbar --\u003e\n\u003clivewire:ckeditor5-ui-part\n    name=\"toolbar\"\n    editorId=\"decoupled-editor\"\n    class=\"my-4\"\n/\u003e\n\n\u003c!-- Separate editable area --\u003e\n\u003clivewire:ckeditor5-editable\n    editorId=\"decoupled-editor\"\n    class=\"border border-gray-300 rounded-xs\"\n    editableClass=\"p-4\"\n    content=\"\u003cp\u003eThis is the initial content of the decoupled editor editable.\u003c/p\u003e\"\n/\u003e\n```\n\n### Multiroot editor 🌳\n\nAdvanced editor supporting multiple separate editing areas (roots) with a shared toolbar. Perfect for complex documents with multiple editable sections like headers, sidebars, and main content.\n\n![CKEditor 5 Multiroot Editor in Livewire application](docs/multiroot-editor.png)\n\n```blade\n\u003c!-- CDN assets in \u003chead\u003e --\u003e\n\u003cx-ckeditor5-assets /\u003e\n\n\u003c!-- Editor instance with multiple roots --\u003e\n\u003clivewire:ckeditor5\n    editorId=\"multiroot-editor\"\n    editorType=\"multiroot\"\n    :content=\"[\n        'header' =\u003e '\u003ch1\u003eDocument Header\u003c/h1\u003e',\n        'content' =\u003e '\u003cp\u003eMain document content goes here.\u003c/p\u003e',\n        'footer' =\u003e '\u003cp\u003eDocument footer\u003c/p\u003e'\n    ]\"\n/\u003e\n\n\u003c!-- Shared toolbar --\u003e\n\u003clivewire:ckeditor5-ui-part\n    name=\"toolbar\"\n    editorId=\"multiroot-editor\"\n    class=\"mb-4\"\n/\u003e\n\n\u003c!-- Header root --\u003e\n\u003clivewire:ckeditor5-editable\n    editorId=\"multiroot-editor\"\n    rootName=\"header\"\n    class=\"mb-4 border border-gray-300 rounded\"\n    editableClass=\"p-4\"\n/\u003e\n\n\u003c!-- Main content root --\u003e\n\u003clivewire:ckeditor5-editable\n    editorId=\"multiroot-editor\"\n    rootName=\"content\"\n    class=\"mb-4 border border-gray-300 rounded\"\n    editableClass=\"p-4\"\n/\u003e\n\n\u003c!-- Footer root --\u003e\n\u003clivewire:ckeditor5-editable\n    editorId=\"multiroot-editor\"\n    rootName=\"footer\"\n    class=\"border border-gray-300 rounded\"\n    editableClass=\"p-4\"\n/\u003e\n```\n\n## Advanced configuration ⚙️\n\n### Livewire Sync 🔄\n\nEnable real-time synchronization between the editor and your Livewire component. Content changes are automatically sent to the server with configurable debouncing for performance optimization.\n\n![CKEditor 5 Livewire Sync demo](docs/livewire-sync.gif)\n\n#### Two way binding using `wire:model` ⛓️\n\nBind the editor content to a Livewire property with optional debounce to control update frequency. This is useful for reducing server load during rapid content changes.\n\n```blade\n\u003clivewire:ckeditor5\n    wire:model.live=\"content\"\n    :saveDebounceMs=\"500\"\n/\u003e\n```\n\nHandle content changes in your Livewire component:\n\n```php\nclass Editor extends Component\n{\n    public $content = [ 'content' =\u003e '\u003cp\u003eInitial content\u003c/p\u003e' ];\n\n    public function render()\n    {\n        return view('livewire.editor');\n    }\n\n    public function resetContent()\n    {\n        $this-\u003econtent = ['content' =\u003e ''];\n    }\n}\n```\n\n#### Bidirectional Communication using Events 🔄\n\nThe package provides bidirectional communication between Livewire and the editor through custom events.\n\n##### Editor → Livewire: Content Change Event 📤\n\nThe editor automatically dispatches the `editor-content-changed` event whenever the content is modified.\n\n```php\nnamespace App\\Livewire;\n\nuse Livewire\\Component;\nuse Livewire\\Attributes\\On;\n\nclass ContentMonitor extends Component\n{\n    public array $content = ['main' =\u003e '\u003cp\u003eInitial content\u003c/p\u003e'];\n    public string $editorId = 'my-editor';\n\n    #[On('editor-content-changed')]\n    public function onEditorContentChanged(string $editorId, array $content): void\n    {\n        if ($editorId === $this-\u003eeditorId) {\n            $this-\u003econtent = $content;\n            // Your custom logic here\n        }\n    }\n\n    public function render()\n    {\n        return view('livewire.content-monitor');\n    }\n}\n```\n\n##### Livewire → Editor: Set Content Event 📥\n\nUpdate the editor content from your Livewire component by dispatching the `set-editor-content` event.\n\n```php\nnamespace App\\Livewire;\n\nuse Livewire\\Component;\n\nclass EditorDemo extends Component\n{\n    public string $editorId = 'my-editor';\n\n    public function loadContent(): void\n    {\n        $this-\u003edispatch(\n            'set-editor-content',\n            editorId: $this-\u003eeditorId,\n            content: ['main' =\u003e '\u003cp\u003eNew content loaded!\u003c/p\u003e']\n        );\n    }\n\n    public function render()\n    {\n        return view('livewire.editor-demo');\n    }\n}\n```\n\n```blade\n\u003c!-- resources/views/livewire/editor-demo.blade.php --\u003e\n\u003cdiv\u003e\n    \u003cbutton wire:click=\"loadContent\"\u003eLoad Content\u003c/button\u003e\n\n    \u003clivewire:ckeditor5 :editorId=\"$editorId\" /\u003e\n\u003c/div\u003e\n```\n\n\u003e [!IMPORTANT]\n\u003e Do not use `wire:model` together with these events on the same editor instance, as the broadcasted value might be overwritten by Livewire's internal synchronization.\n\n### Focus Tracking 👁️\n\nYou can track the focus and blur events of the editor by listening for the `editor-focus-changed` event. This event is dispatched with the editor ID and a boolean indicating whether the editor is focused.\n\n```php\n// app/Livewire/FocusDemo.php\nnamespace App\\Livewire;\n\nuse Livewire\\Component;\nuse Livewire\\Attributes\\On;\n\nclass FocusDemo extends Component\n{\n    public bool $isFocused = false;\n    public string $editorId = 'focus-demo-editor';\n\n    #[On('editor-focus-changed')]\n    public function onEditorFocusChanged(string $editorId, bool $focused): void\n    {\n        if ($editorId === $this-\u003eeditorId) {\n            $this-\u003eisFocused = $focused;\n        }\n    }\n\n    public function render()\n    {\n        return view('livewire.focus-demo');\n    }\n}\n```\n\n```blade\n\u003c!-- resources/views/livewire/focus-demo.blade.php --\u003e\n\u003cdiv\u003e\n    \u003cp class=\"mb-4\"\u003e\n        Editor focus state:\n        \u003cspan class=\"font-bold {{ $isFocused ? 'text-green-500' : 'text-red-500' }}\"\u003e\n            {{ $isFocused ? 'Focused' : 'Not Focused' }}\n        \u003c/span\u003e\n    \u003c/p\u003e\n\n    \u003clivewire:ckeditor5\n        :editorId=\"$editorId\"\n        content='\u003cp\u003eThis editor demonstrates the focus event.\u003c/p\u003e'\n    /\u003e\n\u003c/div\u003e\n```\n\n### Watchdog 🐶\n\nBy default, the `\u003clivewire:ckeditor5\u003e` component uses a built-in watchdog mechanism to automatically restart the editor if it crashes (e.g., due to a JavaScript error). The watchdog periodically saves the editor's content and restores it after a crash, minimizing the risk of data loss for users.\n\n#### How it works ⚙️\n\n- If the editor crashes, it is automatically restarted without requiring a page reload.\n- The editor's content is periodically saved in the browser's memory.\n- After a restart, the last saved content is automatically restored.\n\nThis feature is especially useful in applications where reliability and data safety are important.\n\n#### Disabling the watchdog 🚫\n\nThe watchdog is enabled by default. To disable it, set the `watchdog` attribute to `false`:\n\n```blade\n\u003clivewire:ckeditor5\n    content=\"\u003cp\u003eInitial content\u003c/p\u003e\"\n    :watchdog=\"false\"\n/\u003e\n```\n\n## Context 🤝\n\nThe **context** feature is designed to group multiple editor instances together, allowing them to share a common context. This is particularly useful in collaborative editing scenarios, where users can work together in real time. By sharing a context, editors can synchronize features such as comments, track changes, and presence indicators across different editor instances. This enables seamless collaboration and advanced workflows in your Phoenix application.\n\nFor more information about the context feature, see the [CKEditor 5 Context documentation](https://ckeditor.com/docs/ckeditor5/latest/features/collaboration/context-and-collaboration-features.html).\n\n![CKEditor 5 Context in Livewire application](docs/context.png)\n\n### Basic usage 🔧\n\nDefine your context in configuration (`config/ckeditor5.php`):\n\n```php\nreturn [\n    'contexts' =\u003e [\n        'my-context' =\u003e [\n            'config' =\u003e [\n                'plugins' =\u003e [\n                    'CustomContextPlugin'\n                ]\n            ],\n            'watchdogConfig' =\u003e [\n                'crashNumberLimit' =\u003e 20\n            ]\n        ]\n    ],\n    'presets' =\u003e [\n        // ...\n    ]\n];\n```\n\nAnd use it in your Blade template:\n\n```blade\n\u003c!-- Create a context --\u003e\n\u003clivewire:ckeditor5-context contextId=\"my-context\" /\u003e\n\n\u003c!-- Editor 1 using the context --\u003e\n\u003clivewire:ckeditor5\n    contextId=\"my-context\"\n    content=\"Content 1\"\n/\u003e\n\n\u003c!-- Editor 2 using the same context --\u003e\n\u003clivewire:ckeditor5\n    class=\"mt-6\"\n    contextId=\"my-context\"\n    content=\"Content 2\"\n/\u003e\n```\n\n### Custom context translations 🌐\n\nDefine your custom translations in the configuration:\n\n```php\nreturn [\n    'contexts' =\u003e [\n        'custom' =\u003e [\n            // ...\n            'customTranslations' =\u003e [\n                'en' =\u003e [\n                    'Bold' =\u003e 'Custom Bold',\n                    'Italic' =\u003e 'Custom Italic'\n                ],\n                'pl' =\u003e [\n                    'Bold' =\u003e 'Pogrubiony',\n                    'Italic' =\u003e 'Kursywa'\n                ]\n            ]\n        ]\n    ]\n];\n```\n\nThese translations will be used in the context's editors, overriding the default translations.\n\n## Custom plugins 🧩\n\nTo register a custom plugin, use the `registerCustomEditorPlugin` function. This function takes the plugin name and the plugin _reader_ that returns a class extending `Plugin`.\n\n```javascript\nimport { CustomEditorPluginsRegistry as Registry } from 'ckeditor5-livewire';\n\nconst unregister = Registry.the.register('MyCustomPlugin', async () =\u003e {\n  // It's recommended to use lazy import to\n  // avoid bundling ckeditor code in your application bundle.\n  const { Plugin } = await import('ckeditor5');\n\n  return class extends Plugin {\n    static get pluginName() {\n      return 'MyCustomPlugin';\n    }\n\n    init() {\n      console.log('MyCustomPlugin initialized');\n      // Custom plugin logic here\n    }\n  };\n});\n```\n\nIn order to use the plugin you need to extend your config in `config/config.php`:\n\n```php\n'presets' =\u003e [\n    'default' =\u003e [\n        'config' =\u003e [\n            'plugins' =\u003e [\n                'MyCustomPlugin',\n                // other plugins...\n            ],\n            'toolbar' =\u003e [\n                'items' =\u003e [\n                    'myCustomButton',\n                    // other toolbar items...\n                ]\n            ]\n        ]\n    ]\n];\n```\n\nIt must be called before the editor is initialized. You can unregister the plugin later by calling the returned function:\n\n```javascript\nunregister();\n// or CustomEditorPluginsRegistry.the.unregister('MyCustomPlugin');\n```\n\nIf you want to de-register all registered plugins, you can use the `unregisterAll` method:\n\n```javascript\nimport { CustomEditorPluginsRegistry } from 'ckeditor5-livewire';\n\nCustomEditorPluginsRegistry.the.unregisterAll();\n```\n\n## Development ⚙️\n\nTo start the development environment, run:\n\n```bash\npnpm run dev\n```\n\nThe playground app will be available at [http://localhost:8000](http://localhost:8000).\n\n### Running Tests 🧪\n\nThe project includes comprehensive PHP unit tests with 100% code coverage requirement:\n\n```bash\n# Run all tests\ncomposer test\n\n# Run tests with coverage report (requires pcov)\ncomposer test:coverage\n```\n\n## Psst... 👀\n\nIf you're looking for similar stuff, check these out:\n\n- [ckeditor5-phoenix](https://github.com/Mati365/ckeditor5-phoenix)\n  Seamless CKEditor 5 integration for Phoenix Framework. Plug \u0026 play support for LiveView forms with dynamic content, localization, and custom builds.\n\n- [ckeditor5-rails](https://github.com/Mati365/ckeditor5-rails)\n  Smooth CKEditor 5 integration for Ruby on Rails. Works with standard forms, Turbo, and Hotwire. Easy setup, custom builds, and localization support.\n\n- [ckeditor5-symfony](https://github.com/Mati365/ckeditor5-symfony)\n  Native CKEditor 5 integration for Symfony. Works with Symfony 6.x+, standard forms and Twig. Supports custom builds, multiple editor configurations, asset management, and localization. Designed to be simple, predictable, and framework-native.\n\n## Trademarks 📜\n\nCKEditor® is a trademark of [CKSource Holding sp. z o.o.](https://cksource.com/) All rights reserved. For more information about the license of CKEditor® please visit [CKEditor's licensing page](https://ckeditor.com/legal/ckeditor-oss-license/).\n\nThis package is not owned by CKSource and does not use the CKEditor® trademark for commercial purposes. It should not be associated with or considered an official CKSource product.\n\n## License 📜\n\nThis project is licensed under the terms of the [MIT LICENSE](LICENSE).\n\nThis project injects CKEditor 5 which is licensed under the terms of [GNU General Public License Version 2 or later](https://www.gnu.org/licenses/old-licenses/gpl-2.0.html). For more information about CKEditor 5 licensing, please see their [official documentation](https://ckeditor.com/legal/ckeditor-oss-license/).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmati365%2Fckeditor5-livewire","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmati365%2Fckeditor5-livewire","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmati365%2Fckeditor5-livewire/lists"}