{"id":25040659,"url":"https://github.com/Mati365/ckeditor5-rails","last_synced_at":"2025-10-20T23:31:29.000Z","repository":{"id":260316609,"uuid":"867579180","full_name":"Mati365/ckeditor5-rails","owner":"Mati365","description":"🚀 CKEditor 5 Ruby gem - seamless integration with Rails through web components and helper methods. 💎 Supports both GPL and commercial licenses with flexible CDN options and translations. 🎨 Easy configuration with presets, extensive plugin system, and modern async loading.","archived":false,"fork":false,"pushed_at":"2025-02-05T08:24:11.000Z","size":910,"stargazers_count":24,"open_issues_count":0,"forks_count":2,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-02-05T09:25:56.181Z","etag":null,"topics":["cdn","ckeditor5","hetzner","integration","podman","rails","rich-text-editor","ror","ruby","text-editor","webcomponents"],"latest_commit_sha":null,"homepage":"https://ckeditor5-rails.mati365.ovh","language":"Ruby","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":"CHANGELOG.md","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}},"created_at":"2024-10-04T10:29:50.000Z","updated_at":"2025-02-05T08:23:53.000Z","dependencies_parsed_at":"2024-10-30T17:44:13.423Z","dependency_job_id":"b9228fee-d337-4ae5-89cb-7890518fd5f9","html_url":"https://github.com/Mati365/ckeditor5-rails","commit_stats":{"total_commits":17,"total_committers":1,"mean_commits":17.0,"dds":0.0,"last_synced_commit":"aca910adf5783141ff4db058fd1cbcc6eb9e73f1"},"previous_names":["mati365/ckeditor5-rails"],"tags_count":46,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mati365%2Fckeditor5-rails","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mati365%2Fckeditor5-rails/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mati365%2Fckeditor5-rails/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mati365%2Fckeditor5-rails/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Mati365","download_url":"https://codeload.github.com/Mati365/ckeditor5-rails/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":237275559,"owners_count":19283586,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["cdn","ckeditor5","hetzner","integration","podman","rails","rich-text-editor","ror","ruby","text-editor","webcomponents"],"created_at":"2025-02-06T03:03:37.854Z","updated_at":"2025-10-20T23:31:28.993Z","avatar_url":"https://github.com/Mati365.png","language":"Ruby","funding_links":[],"categories":["Ruby","Integrations"],"sub_categories":[],"readme":"# CKEditor 5 Rails Integration ✨\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square)](LICENSE)\n![NPM Version](https://img.shields.io/npm/v/ckeditor5-rails?style=flat-square)\n[![Gem Version](https://img.shields.io/gem/v/ckeditor5?style=flat-square)](https://rubygems.org/gems/ckeditor5)\n[![Gem Total Downloads](https://img.shields.io/gem/dt/ckeditor5?style=flat-square\u0026color=orange)](https://rubygems.org/gems/ckeditor5)\n[![Coverage](https://img.shields.io/codecov/c/github/mati365/ckeditor5-rails?style=flat-square)](https://codecov.io/gh/mati365/ckeditor5-rails)\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-rails?style=flat-square)\n[![GitHub issues](https://img.shields.io/github/issues/mati365/ckeditor5-rails?style=flat-square)](https://github.com/Mati365/ckeditor5-rails/issues)\n\nCKEditor 5 Ruby on Rails integration gem. Provides seamless integration of CKEditor 5 with Rails applications through web components and helper methods. This gem supports various editor types, including classic, inline, balloon, and decoupled editors. It also includes support for custom plugins, translations, and configuration options.\n\n**Requirements:**\n  * Ruby \u003e= 2.5\n  * Rails \u003e= 5.0\n\n\u003e [!IMPORTANT]\n\u003e This gem 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 Ruby on Rails application\"\u003e\n\u003c/p\u003e\n\n## Installation 🛠️\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'ckeditor5'\n```\n\n\u003e [!NOTE]\n\u003e This gem uses importmaps and does not require Webpacker or any other JavaScript bundler. It's compatible with Rails 6.0+ and `importmap-rails` gem.\n\u003e While installation is simplified, it's recommended to check if jsdelivr or unpkg CDN is accessible in your environment, otherwise, you may need to configure a custom CDN (or use a commercial one).\n\nIn your layout:\n\n```erb\n\u003c!-- app/views/layouts/application.html.erb --\u003e\n\n\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n  \u003chead\u003e\n    \u003c!--\n      ⚠️ **Important**: When using `importmap-rails`, make sure the importmap\n      tags are rendered after `ckeditor5_assets` helper. In this scenario,\n      content is yielded before rendering `javascript_importmap_tags`.\n\n      If you are not using `importmap-rails`, you can ignore this note and just\n      include `ckeditor5_assets` helper in the head section of your layout (or using `content_for`).\n    --\u003e\n    \u003c!-- javascript_importmap_tags --\u003e\n\n    \u003c%= yield :head %\u003e\n  \u003c/head\u003e\n  \u003cbody\u003e\n    \u003c%= yield %\u003e\n  \u003c/body\u003e\n\u003c/html\u003e\n```\n\nIn your view:\n\n```erb\n\u003c!-- app/views/demos/index.html.erb --\u003e\n\n\u003c% content_for :head do %\u003e\n  \u003c!-- 📦 Adds importmap with CKEditor 5 assets. --\u003e\n  \u003c!-- 🌍 It'll automatically use your `I18n.locale` language. --\u003e\n  \u003c%= ckeditor5_assets %\u003e\n\u003c% end %\u003e\n\n\u003c!-- 🖋️ CKEditor 5 might be placed using simple view helper ... --\u003e\n\u003c%= ckeditor5_editor %\u003e\n\n\u003c!-- ... or using form input helper --\u003e\n\n\u003c%= form_for @post do |f| %\u003e\n  \u003c%= f.ckeditor5 :content, required: true %\u003e\n\u003c% end %\u003e\n```\n\n(optional) Customize your config (the default config is defined [here](https://github.com/Mati365/ckeditor5-rails/blob/main/lib/ckeditor5/rails/presets/manager.rb)):\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # 🔖 Specify the version of editor you want.\n  # ⚙️ Default configuration includes:\n  #    📝 Classic editor build\n  #    🧩 Essential plugins (paragraphs, basic styles)\n  #    🎛️ Default toolbar layout\n  #    📜 GPL license\n\n  # Optionally, you can specify version of CKEditor 5 to use.\n  # If it's not specified the default version specified in the gem will be used.\n  # version '47.1.0'\n\n  # Upload images to the server using the simple upload adapter, instead of Base64 encoding.\n  # simple_upload_adapter\n\n  # Specify global language for the editor.\n  # It can be done here, in controller or in the view.\n  # By default the `I18n.locale` is used.\n  # language :pl\nend\n```\n\nVoilà! You have CKEditor 5 integrated with your Rails application. 🎉\n\n## Try Demos! 🎮 ✨\n\nExplore various editor configurations with the interactive [demo application](https://github.com/Mati365/ckeditor5-rails/tree/main/sandbox/app/views/demos). For additional inspiration, visit the official CKEditor 5 [examples](https://ckeditor.com/docs/ckeditor5/latest/examples/builds/classic-editor.html).\n\nTo run the demos locally, follow these steps:\n\n```bash\nbundle install # Install dependencies\nbundle exec guard -g rails # Start the server\n```\n\nOpen [http://localhost:3000/](http://localhost:3000/) in a browser to start experimenting. Modify the code as needed.\n\nFor extending CKEditor's functionality, refer to the [plugins directory](https://github.com/Mati365/ckeditor5-rails/tree/main/lib/ckeditor5/rails/plugins) to create custom plugins. Community contributions are welcome.\n\n## Table of Contents 📚\n\n- [CKEditor 5 Rails Integration ✨](#ckeditor-5-rails-integration-)\n  - [Installation 🛠️](#installation-️)\n  - [Try Demos! 🎮 ✨](#try-demos--)\n  - [Table of Contents 📚](#table-of-contents-)\n  - [Presets 🎨](#presets-)\n    - [Automatic upgrades 🔄](#automatic-upgrades-)\n    - [Available Configuration Methods ⚙️](#available-configuration-methods-️)\n      - [`cdn(cdn = nil, \u0026block)` method](#cdncdn--nil-block-method)\n      - [`version(version, apply_patches: true)` method](#versionversion-apply_patches-true-method)\n      - [`automatic_upgrades(enabled: true)` method](#automatic_upgradesenabled-true-method)\n      - [`gpl` method](#gpl-method)\n      - [`license_key(key)` method](#license_keykey-method)\n      - [`premium` method](#premium-method)\n      - [`editable_height(height)` method](#editable_heightheight-method)\n      - [`language(ui, content:)` method](#languageui-content-method)\n      - [`translations(*languages)` method](#translationslanguages-method)\n      - [`ckbox` method](#ckbox-method)\n      - [`type(type)` method](#typetype-method)\n      - [`toolbar(*items, should_group_when_full: true, \u0026block)` method](#toolbaritems-should_group_when_full-true-block-method)\n      - [`block_toolbar(*items, should_group_when_full: true, \u0026block)` method](#block_toolbaritems-should_group_when_full-true-block-method)\n      - [`balloon_toolbar(*items, should_group_when_full: true, \u0026block)` method](#balloon_toolbaritems-should_group_when_full-true-block-method)\n      - [`menubar(visible: true)` method](#menubarvisible-true-method)\n      - [`configure(name, value)` method](#configurename-value-method)\n      - [`plugin(name, premium:, import_name:)` method](#pluginname-premium-import_name-method)\n      - [`plugins(*names, **kwargs)` method](#pluginsnames-kwargs-method)\n      - [`inline_plugin(name, code)` method](#inline_pluginname-code-method)\n      - [`external_plugin(name, script:, import_as: nil, window_name: nil, stylesheets: [])` method](#external_pluginname-script-import_as-nil-window_name-nil-stylesheets--method)\n      - [`patch_plugin(plugin)`](#patch_pluginplugin)\n      - [`apply_integration_patches(compress: false)` method](#apply_integration_patchescompress-false-method)\n      - [`simple_upload_adapter(url, compress: true)` method](#simple_upload_adapterurl-compress-true-method)\n      - [`special_characters(compress: true, \u0026block)` method](#special_characterscompress-true-block-method)\n      - [`wproofreader(version: nil, cdn: nil, compress: true, **config)` method](#wproofreaderversion-nil-cdn-nil-compress-true-config-method)\n      - [`custom_translations(lang_code = nil, translations = {}, compress: true)` method](#custom_translationslang_code--nil-translations---compress-true-method)\n      - [`compression(enabled: true)` method](#compressionenabled-true-method)\n    - [Controller / View helpers 📦](#controller--view-helpers-)\n      - [`ckeditor5_translation_ref(key)` method](#ckeditor5_translation_refkey-method)\n      - [`ckeditor5_element_ref(selector)` method](#ckeditor5_element_refselector-method)\n      - [`ckeditor5_preset(name = nil, \u0026block)` method](#ckeditor5_presetname--nil-block-method)\n  - [Including CKEditor 5 assets 📦](#including-ckeditor-5-assets-)\n    - [Format 📝](#format-)\n      - [Using default preset](#using-default-preset)\n      - [Custom preset](#custom-preset)\n      - [Inline preset definition](#inline-preset-definition)\n    - [Lazy loading 🚀](#lazy-loading-)\n      - [`ckeditor5_lazy_javascript_tags` helper](#ckeditor5_lazy_javascript_tags-helper)\n    - [GPL usage 🆓](#gpl-usage-)\n    - [Commercial usage 💰](#commercial-usage-)\n  - [Editor placement 🏗️](#editor-placement-️)\n    - [Setting Initial Content 📝](#setting-initial-content-)\n    - [Watchdog 🐕](#watchdog-)\n    - [Classic editor 📝](#classic-editor-)\n    - [Multiroot editor 🌳](#multiroot-editor-)\n    - [Inline editor 📝](#inline-editor-)\n    - [Balloon editor 🎈](#balloon-editor-)\n    - [Decoupled editor 🌐](#decoupled-editor-)\n  - [Using Context 📦](#using-context-)\n    - [Using Context in CKEditor 5 🔄](#using-context-in-ckeditor-5-)\n    - [Example usage of `ckeditor5_context` helper 📝](#example-usage-of-ckeditor5_context-helper-)\n  - [How to access editor instance? 🤔](#how-to-access-editor-instance-)\n  - [Common Tasks and Solutions 💡](#common-tasks-and-solutions-)\n    - [Setting Editor Language 🌐](#setting-editor-language-)\n      - [Setting the language in the assets helper](#setting-the-language-in-the-assets-helper)\n      - [Setting the language in the initializer](#setting-the-language-in-the-initializer)\n      - [Setting the language on the editor level](#setting-the-language-on-the-editor-level)\n      - [Preloading multiple translation packs](#preloading-multiple-translation-packs)\n    - [Spell and Grammar Checking 📝](#spell-and-grammar-checking-)\n    - [Integrating with Forms 📋](#integrating-with-forms-)\n      - [Rails form builder integration](#rails-form-builder-integration)\n      - [Simple form integration](#simple-form-integration)\n    - [Integration with Turbolinks 🚀](#integration-with-turbolinks-)\n    - [Custom Styling 🎨](#custom-styling-)\n    - [Custom plugins 🧩](#custom-plugins-)\n    - [Content Security Policy (CSP) 🛡️](#content-security-policy-csp-️)\n  - [Events fired by the editor 🔊](#events-fired-by-the-editor-)\n    - [`editor-ready` event](#editor-ready-event)\n    - [`editor-error` event](#editor-error-event)\n    - [`editor-change` event](#editor-change-event)\n    - [Inline event handling](#inline-event-handling)\n  - [Gem Development 🛠](#gem-development-)\n    - [Building NPM package 📦](#building-npm-package-)\n    - [Running tests 🧪](#running-tests-)\n  - [Psst... 👀](#psst-)\n  - [Trademarks 📜](#trademarks-)\n  - [License 📜](#license-)\n\n## Presets 🎨\n\nPresets are predefined configurations of CKEditor 5, allowing quick setup with specific features. The gem includes a `:default` preset with common features like bold, italic, underline, and link for the classic editor.\n\nYou can create your own by defining it in the `config/initializers/ckeditor5.rb` file using the `config.presets.define` method. The example below illustrates the setup of a custom preset with a classic editor and a custom toolbar:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # It's possible to override the default preset right in the initializer.\n  version '47.1.0'\n\n  # New presets inherit properties from the default preset defined in the initializer.\n  # In this example, the custom preset inherits everything from default but disables the menubar:\n  presets.define :inherited_custom\n    menubar visible: false\n  end\n\n  # In order to define preset from scratch, you can use the `inherit: false` option.\n  presets.define :blank_preset, inherit: false do\n    version '47.1.0'\n\n    # It tells the integration to fetch the newest security patches and bug fixes.\n    # It may be disabled, but it's highly recommended to keep it enabled to avoid\n    # potential security issues.\n    automatic_upgrades\n\n    gpl\n    type :classic\n\n    menubar\n    toolbar :undo, :redo, :|, :heading, :|, :bold, :italic, :underline, :|,\n            :link, :insertImage, :mediaEmbed, :insertTable, :blockQuote, :|,\n            :bulletedList, :numberedList, :todoList, :outdent, :indent\n\n    plugins :AccessibilityHelp, :Autoformat, :AutoImage, :Autosave,\n            :BlockQuote, :Bold, :CloudServices,\n            :Essentials, :Heading, :ImageBlock, :ImageCaption, :ImageInline,\n            :ImageInsert, :ImageInsertViaUrl, :ImageResize, :ImageStyle,\n            :ImageTextAlternative, :ImageToolbar, :ImageUpload, :Indent,\n            :IndentBlock, :Italic, :Link, :LinkImage, :List, :ListProperties,\n            :MediaEmbed, :Paragraph, :PasteFromOffice, :PictureEditing,\n            :SelectAll, :Table, :TableCaption, :TableCellProperties,\n            :TableColumnResize, :TableProperties, :TableToolbar,\n            :TextTransformation, :TodoList, :Underline, :Undo, :Base64UploadAdapter\n\n    configure :image, {\n      toolbar: ['imageTextAlternative', 'imageStyle:inline', 'imageStyle:block', 'imageStyle:side']\n    }\n  end\nend\n```\n\nIn order to override existing presets, you can use the `presets.override` method. The method takes the name of the preset you want to override and a block with the old configuration. The example below shows how to hide the menubar in the default preset:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  presets.override :custom do\n    menubar visible: false\n\n    toolbar do\n      remove :underline, :heading\n    end\n  end\nend\n```\n\nYou can define presets in the controller using the `ckeditor5_preset` helper method. See it in the section below ([Controller / View helpers](#controller--view-helpers-)).\n\nConfiguration of the editor can be complex, and it's recommended to use the [CKEditor 5 online builder](https://ckeditor.com/ckeditor-5/online-builder/) to generate the configuration. It allows you to select the features you want to include and generate the configuration code in JavaScript format. Keep in mind that you need to convert the JavaScript configuration to Ruby format before using it in this gem.\n\n### Automatic upgrades 🔄\n\nThe gem includes a feature that automatically upgrades the CKEditor\u0026nbsp;5 version when it's released. It's enabled by default for the `:default` preset. It means that the editor will automatically check the version of the editor during the initialization and upgrade it to the latest version if the new patch or minor version is released.\n\nIf you want to disable automatic upgrades, you can pass the `enabled: false` keyword argument to the `automatic_upgrades` method.\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  automatic_upgrades enabled: false\nend\n```\n\n### Available Configuration Methods ⚙️\n\n#### `cdn(cdn = nil, \u0026block)` method\n\n\u003cdetails\u003e\n  \u003csummary\u003eConfigure custom CDN URL pattern or use predefined CDNs like jsdelivr or unpkg\u003c/summary\u003e\n\n\u003cbr /\u003e\n\nDefines the CDN to be used for CKEditor 5 assets. The example below shows how to set the CDN to `:jsdelivr`:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  cdn :jsdelivr\nend\n```\n\nIt also allows you to define a custom CDN by passing a block with the bundle, version, and path arguments. The example below shows how to define it for the `jsdelivr` CDN:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  cdn do |bundle, version, path|\n    base_url = \"https://cdn.jsdelivr.net/npm/#{bundle}@#{version}/dist\"\n\n    \"#{base_url}/#{path.start_with?('translations/') ? '' : 'browser/'}#{path}\"\n  end\nend\n```\n\u003c/details\u003e\n\n#### `version(version, apply_patches: true)` method\n\n\u003cdetails\u003e\n  \u003csummary\u003eSet up the version of CKEditor 5 to be used by the integration\u003c/summary\u003e\n\n\u003cbr /\u003e\n\nDefines the version of CKEditor 5 to be used. The example below shows how to set the version to `43.2.0`:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  version '47.1.0'\nend\n```\n\nIn order to disable default patches, you can pass the `apply_patches: false` keyword argument to the `version` method.\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  version '47.1.0', apply_patches: false\nend\n```\n\nThe patches are defined in the `lib/ckeditor5/rails/plugins/patches` directory. If you want to apply custom patches, you can use the `patch_plugin` method.\n\n\u003c/details\u003e\n\n#### `automatic_upgrades(enabled: true)` method\n\n\u003cdetails\u003e\n  \u003csummary\u003eEnable or disable automatic security patches and bug fixes\u003c/summary\u003e\n\n\u003cbr /\u003e\n\nDefines if automatic upgrades should be enabled. It's enabled for the `:default` preset by default. The example below shows how to disable automatic upgrades:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  automatic_upgrades enabled: false\nend\n```\n\nIt means that the editor will automatically upgrade to the latest version when the gem is updated. It'll upgrade the editor only if the new patch or minor version is released. If you want to disable automatic upgrades, you can pass the `enabled: false` keyword argument to the `automatic_upgrades` method.\n\nVersion is checked every nth day, where n is the number of days since the last check. Currently it's 4 days.\n\u003c/details\u003e\n\n#### `gpl` method\n\n\u003cdetails\u003e\n  \u003csummary\u003eDefines the license of CKEditor 5. The example below shows how to set the license to GPL:\u003c/summary\u003e\n\n\u003cbr /\u003e\n\nDefines the license of CKEditor 5. The example below shows how to set the license to GPL:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  gpl\nend\n```\n\u003c/details\u003e\n\n#### `license_key(key)` method\n\n\u003cdetails\u003e\n  \u003csummary\u003eDefines the license key of CKEditor 5. It calls `premium` method internally. The example below shows how to set the license key:\u003c/summary\u003e\n\n\u003cbr /\u003e\n\nDefines the license key of CKEditor 5. It calls `premium` method internally. The example below shows how to set the license key:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  license_key 'your-license-key'\nend\n```\n\u003c/details\u003e\n\n#### `premium` method\n\n\u003cdetails\u003e\n  \u003csummary\u003eDefines if premium package should be included in JS assets. The example below shows how to add `ckeditor5-premium-features` to import maps:\u003c/summary\u003e\n\n\u003cbr /\u003e\n\nDefines if premium package should be included in JS assets. The example below shows how to add `ckeditor5-premium-features` to import maps:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  premium\nend\n```\n\u003c/details\u003e\n\n#### `editable_height(height)` method\n\n\u003cdetails\u003e\n  \u003csummary\u003eSet editor height in pixels - useful for fixed-size layouts\u003c/summary\u003e\n\n\u003cbr /\u003e\n\nDefines the height of the editor. The example below shows how to set the height to `300px`:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  editable_height 300\nend\n```\n\u003c/details\u003e\n\n#### `language(ui, content:)` method\n\n\u003cdetails\u003e\n  \u003csummary\u003eSet UI and content language for the editor\u003c/summary\u003e\n\n\u003cbr /\u003e\n\nDefines the language of the editor. You can pass the language code as an argument. Keep in mind that the UI and content language can be different. The example below shows how to set the Polish language for the UI and content:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  language :pl\nend\n```\n\nIn order to set the language for the content, you can pass the `content` keyword argument:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  language :pl, content: :en\nend\n```\n\nThe example above sets the Polish language for the UI and content. If `pl` language was not defined in the translations, the builder will append the language to the list of translations to fetch. In order to prefetch more translations, use the helper below.\n\n\u003c/details\u003e\n\n#### `translations(*languages)` method\n\n\u003cdetails\u003e\n  \u003csummary\u003eLoad additional language files for the editor interface\u003c/summary\u003e\n\n\u003cbr /\u003e\n\nDefines the translations of CKEditor 5. You can pass the language codes as arguments. The example below shows how tell integration to fetch Polish and Spanish translations:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  translations :pl, :es\nend\n```\n\n⚠️ You need to use `language` method to set the default language of the editor, as the `translations` only fetch the translations files and makes them available to later use.\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  translations :pl\n  language :pl\nend\n```\n\u003c/details\u003e\n\n#### `ckbox` method\n\n\u003cdetails\u003e\n  \u003csummary\u003eConfigure CKBox file manager integration\u003c/summary\u003e\n\n\u003cbr /\u003e\n\nDefines the CKBox plugin to be included in the editor. The example below shows how to include the CKBox plugin:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  ckbox '2.6.0', theme: :lark\nend\n```\n\u003c/details\u003e\n\n#### `type(type)` method\n\n\u003cdetails\u003e\n  \u003csummary\u003eSelect editor type (classic, inline, balloon, decoupled, multiroot)\u003c/summary\u003e\n\n\u003cbr /\u003e\n\nDefines the type of editor. Available options:\n\n- `:classic` - classic edytor\n- `:inline` - inline editor\n- `:decoupled` - decoupled editor\n- `:balloon` - balloon editor\n- `:multiroot` - editor with multiple editing areas\n\nThe example below sets the editor type to `multiroot` in the custom preset:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  type :multiroot\nend\n```\n\u003c/details\u003e\n\n#### `toolbar(*items, should_group_when_full: true, \u0026block)` method\n\n\u003cdetails\u003e\n  \u003csummary\u003eDefine toolbar items and their grouping behavior\u003c/summary\u003e\n\n\u003cbr /\u003e\n\nDefines the toolbar items. You can use predefined items like `:undo`, `:redo`, `:|` or specify custom items. There are a few special items:\n\n- `:_` - breakpoint\n- `:|` - separator\n\nThe `should_group_when_full` keyword argument determines whether the toolbar should group items when there is not enough space. It's set to `true` by default.\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  toolbar :undo, :redo, :|, :heading, :|, :bold, :italic, :underline, :|,\n          :link, :insertImage, :ckbox, :mediaEmbed, :insertTable, :blockQuote, :|,\n          :bulletedList, :numberedList, :todoList, :outdent, :indent\nend\n```\n\nKeep in mind that the order of items is important, and you should install the corresponding plugins. You can find the list of available plugins in the [CKEditor 5 documentation](https://ckeditor.com/docs/ckeditor5/latest/framework/architecture/plugins.html).\n\nIf you want to add or prepend items to the existing toolbar, you can use the block syntax:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  toolbar do\n    append :selectAll, :|, :selectAll, :selectAll\n    # Or prepend: prepend :selectAll, :|, :selectAll, :selectAll\n  end\nend\n```\n\nIf you want to remove items from the toolbar, you can use the `remove` method:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  toolbar do\n    remove :selectAll, :heading #, ...\n  end\nend\n```\n\nIf you want to append groups of items, you can use the `group` method:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  toolbar do\n    group :text_formatting, label: 'Text Formatting', icon: 'threeVerticalDots' do\n      append :bold, :italic, :underline, :strikethrough, separator,\n             :subscript, :superscript, :removeFormat\n    end\n  end\nend\n```\n\nIf you want add new line or the separator, you can use the `break_line` or `separator` methods:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  toolbar do\n    append :bold, break_line\n    append separator, :italic\n  end\nend\n```\n\n\u003c/details\u003e\n\n#### `block_toolbar(*items, should_group_when_full: true, \u0026block)` method\n\n\u003cdetails\u003e\n  \u003csummary\u003eDefine block toolbar items and their grouping behavior\u003c/summary\u003e\n\n\u003cbr /\u003e\n\nAPI is identical to the `toolbar` method, but it's used for block toolbar items. The example below shows how to define block toolbar items:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  block_toolbar :paragraph, :heading, :blockQuote, :|, :bulletedList, :numberedList, :todoList\nend\n```\n\nIt is useful when you want to use Block Balloon Editor or Block Toolbar features.\n\n\u003c/details\u003e\n\n#### `balloon_toolbar(*items, should_group_when_full: true, \u0026block)` method\n\n\u003cdetails\u003e\n  \u003csummary\u003eDefine balloon toolbar items and their grouping behavior\u003c/summary\u003e\n\n\u003cbr /\u003e\n\nAPI is identical to the `toolbar` method, but it's used for balloon toolbar items. The example below shows how to define balloon toolbar items:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  balloon_toolbar :bold, :italic, :underline, :link, :insertImage, :mediaEmbed, :insertTable, :blockQuote\nend\n```\n\nIt is useful when you want to use Balloon Editor or Balloon Toolbar features.\n\n\u003c/details\u003e\n\n#### `menubar(visible: true)` method\n\n\u003cdetails\u003e\n  \u003csummary\u003eSet the visibility and options for the editor menubar\u003c/summary\u003e\n\n\u003cbr /\u003e\n\nDefines the visibility of the menubar. By default, it's set to `true`. In order to hide the menubar, you can pass the `visible: false` keyword argument.\n\nThe example below shows how to set the menubar visibility:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  menubar visible: false\nend\n```\n\u003c/details\u003e\n\n#### `configure(name, value)` method\n\n\u003cdetails\u003e\n  \u003csummary\u003eAdd custom configuration options to the editor instance\u003c/summary\u003e\n\n\u003cbr /\u003e\n\nAllows you to set custom configuration options. You can pass the name of the option and its value as arguments. The [`ckeditor5_element_ref(selector)` helper](#ckeditor5_element_refselector-method) allows you to reference DOM elements that will be used by the editor's features. It's particularly useful for features that need to check element presence or operate on specific DOM elements.\n\nFor example, you can use it to configure font family dropdown to show only fonts available in specific elements:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  configure :fontFamily, {\n    supportAllValues: true,\n    options: [\n      'default',\n      'Arial, Helvetica, sans-serif',\n      'Courier New, Courier, monospace',\n      'Georgia, serif',\n      'Lucida Sans Unicode, Lucida Grande, sans-serif',\n      'Tahoma, Geneva, sans-serif',\n      'Times New Roman, Times, serif',\n      'Trebuchet MS, Helvetica, sans-serif',\n      'Verdana, Geneva, sans-serif'\n    ]\n  }\nend\n```\n\u003c/details\u003e\n\n#### `plugin(name, premium:, import_name:)` method\n\n\u003cdetails\u003e\n  \u003csummary\u003eRegister individual CKEditor plugins with optional premium flag\u003c/summary\u003e\n\n\u003cbr /\u003e\n\nDefines a plugin to be included in the editor. You can pass the name of the plugin as an argument. The `premium` keyword argument determines whether the plugin is premium. The `import_name` keyword argument specifies the name of the package to import the plugin from.\n\nThe example below show how to import Bold plugin from the `ckeditor5` npm package:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  plugin :Bold\nend\n```\n\nIn order to import a plugin from a custom ESM package, you can pass the `import_name` keyword argument:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  plugin :YourPlugin, import_name: 'your-package'\nend\n```\n\nIn order to import a plugin from a custom Window entry, you can pass the `window_name` keyword argument:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  plugin :YourPlugin, window_name: 'YourPlugin'\nend\n```\n\nIf there is no `window.YourPlugin` object, the plugin will dispatch window event to load. To handle this event, you can use the `window.addEventListener` method:\n\n```js\nwindow.addEventListener('ckeditor:request-cjs-plugin:YourPlugin', () =\u003e {\n  window.YourPlugin = (async () =\u003e {\n    const { Plugin } = await import('ckeditor5');\n\n    return class YourPlugin extends Plugin {\n      // Your plugin code\n    };\n  })();\n});\n```\n\n⚠️ The event handler must be attached before the plugin is requested. If the plugin is requested before the event handler is attached, the plugin will not be loaded.\n\n\u003c/details\u003e\n\n#### `plugins(*names, **kwargs)` method\n\n\u003cdetails\u003e\n  \u003csummary\u003eRegister multiple CKEditor plugins at once\u003c/summary\u003e\n\n\u003cbr /\u003e\n\nDefines the plugins to be included in the editor. You can specify multiple plugins by passing their names as arguments. The keyword arguments are identical to the configuration of the `plugin` method defined below.\n\n\u003cbr /\u003e\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  plugins :Bold, :Italic, :Underline, :Link\nend\n```\n\nMethods such as `remove`, `append`, and `prepend` can be used to modify the plugins configuration. To remove a plugin, you can use the `remove` method with the plugin name as an argument:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  plugins do\n    remove :Heading\n  end\nend\n```\n\u003c/details\u003e\n\n#### `inline_plugin(name, code)` method\n\n\u003cdetails\u003e\n  \u003csummary\u003eDefine custom CKEditor plugins directly in the configuration\u003c/summary\u003e\n\n\u003cbr /\u003e\n\n⚠️ **Warning:** Use with caution as this is an inline definition of the plugin code, and it can potentially cause XSS vulnerabilities. Only use this method with static, trusted JavaScript code. In order to pass some dynamic data to such plugin, you can use the `configure` method and override the selected preset in your controller.\n\nThe example below shows how to define a custom plugin that doesn't do anything:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  inline_plugin :MyCustomPlugin, \u003c\u003c~JS\n    const { Plugin } = await import( 'ckeditor5' );\n\n    return class extends Plugin {\n      static get pluginName() {\n        return 'MyCustomPlugin';\n      }\n\n      init() {\n        const config = this.editor.config.get('myCustomPlugin') || {};\n\n        // ... Your plugin code\n      }\n    }\n  JS\nend\n```\n\nTo configure the custom plugin, use the `configure` method in your initializer. The example below shows how to configure the `myCustomPlugin`:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  configure :myCustomPlugin, {\n    option1: 'value1',\n    option2: 'value2'\n  }\nend\n```\n\nThis approach is resistant to XSS attacks as it avoids inline JavaScript.\n\u003c/details\u003e\n\n#### `external_plugin(name, script:, import_as: nil, window_name: nil, stylesheets: [])` method\n\n\u003cdetails\u003e\n  \u003csummary\u003eDefine external CKEditor plugins directly in the configuration\u003c/summary\u003e\n\n\u003cbr /\u003e\n\nDefines an external plugin to be included in the editor. You can pass the name of the plugin as an argument. The `script` keyword argument specifies the URL of the script to import the plugin from. The `import_as` keyword argument specifies the name of the package to import the plugin from. The `window_name` keyword argument specifies the name of the plugin in the window object. The `stylesheets` keyword argument specifies the URLs of the stylesheets to import.\n\nThe example below shows how to define an external plugin that highlights the text:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  external_plugin :MyExternalPlugin,\n                  script: 'https://example.com/my-external-plugin.js'\nend\n```\n\nIn order to import a plugin from a custom ESM package, you can pass the `import_as` keyword argument:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  external_plugin :MyExternalPlugin,\n                  script: 'https://example.com/my-external-plugin.js',\n                  import_as: 'Plugin'\nend\n```\n\nIt's equivalent to the following JavaScript code:\n\n```js\nimport { Plugin } from 'my-external-plugin';\n```\n\nIn order to import a plugin from a custom Window entry, you can pass the `window_name` keyword argument:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  external_plugin :MyExternalPlugin,\n                  script: 'https://example.com/my-external-plugin.js',\n                  window_name: 'MyExternalPlugin'\nend\n```\n\nIt's equivalent to the following JavaScript code:\n\n```js\nconst Plugin = window.MyExternalPlugin;\n```\n\nIn order to import a plugin with stylesheets, you can pass the `stylesheets` keyword argument:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  external_plugin :MyExternalPlugin,\n                  script: 'https://example.com/my-external-plugin.js',\n                  stylesheets: ['https://example.com/my-external-plugin.css']\nend\n```\n\n\u003c/details\u003e\n\n#### `patch_plugin(plugin)`\n\n\u003cdetails\u003e\n  \u003csummary\u003eAppends plugin that applies patch to the specific versions of CKEditor 5\u003c/summary\u003e\n\n\u003cbr /\u003e\n\nDefines a plugin that applies a patch to the specific versions of CKEditor 5. The example below shows how to define a plugin that applies a patch to the `44.1.0` version:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  patch_plugin MyPatchPlugin.new\nend\n```\n\nwhere the `MyPatchPlugin` should inherit from `KEditor5::Rails::Editor::PropsPatchPlugin` and implement the `initialize` method. For example:\n\n```rb\nclass YourPatch \u003c CKEditor5::Rails::Editor::PropsPatchPlugin\n  PLUGIN_CODE = \u003c\u003c~JS\n    const { Plugin, ColorPickerView, debounce } = await import( 'ckeditor5' );\n\n    return class YourPatch extends Plugin {\n      static get pluginName() {\n        return 'YourPatch';\n      }\n\n      constructor(editor) {\n        super(editor);\n\n        // ... your patch\n      }\n    }\n  JS\n\n  def initialize\n    super(:YourPatch, PLUGIN_CODE, min_version: nil, max_version: '45.0.0')\n  end\nend\n```\n\u003c/details\u003e\n\n#### `apply_integration_patches(compress: false)` method\n\n\u003cdetails\u003e\n  \u003csummary\u003eApply patches to the specific versions of CKEditor 5\u003c/summary\u003e\n\n\u003cbr /\u003e\n\nDefines a method that applies patches to the specific versions of CKEditor 5. The example below shows how to apply patches to the `44.1.0` version:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  apply_integration_patches\nend\n```\n\nIt's useful when you want to apply patches to the specific versions of CKEditor 5. The patches are defined in the `lib/ckeditor5/rails/plugins/patches` directory.\n\n\u003c/details\u003e\n\n#### `simple_upload_adapter(url, compress: true)` method\n\n\u003cdetails\u003e\n  \u003csummary\u003eConfigure server-side image upload endpoint\u003c/summary\u003e\n\n\u003cbr /\u003e\n\nDefines the URL for the simple upload adapter. The default endpoint is `/uploads` and the method is `POST`. The example below shows how to set the URL to `/uploads`:\n\n\u003cbr /\u003e\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  simple_upload_adapter\n  # or: simple_upload_adapter '/uploads'\nend\n```\n\u003c/details\u003e\n\n#### `special_characters(compress: true, \u0026block)` method\n\n\u003cdetails\u003e\n  \u003csummary\u003eConfigure special characters plugin\u003c/summary\u003e\n\n\u003cbr /\u003e\n\nDefines the special characters plugin to be included in the editor. The example below shows how to include the special characters plugin:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  special_characters do\n    # Enable built-in packs using symbols\n    packs :Text, :Essentials, :Currency, :Mathematical, :Latin\n\n    # Custom groups\n    group 'Emoji', label: 'Emoticons' do\n      item 'smiley', '😊'\n      item 'heart', '❤️'\n    end\n\n    group 'Arrows',\n          items: [\n            { title: 'right arrow', character: '→' },\n            { title: 'left arrow', character: '←' }\n          ]\n\n    group 'Mixed',\n          items: [{ title: 'star', character: '⭐' }],\n          label: 'Mixed Characters' do\n      item 'heart', '❤️'\n    end\n\n    order :Text, :Currency, :Mathematical, :Latin, :Emoji, :Arrows, :Mixed\n  end\nend\n```\n\nFor more info about the special characters plugin, check the [official documentation](https://ckeditor.com/docs/ckeditor5/latest/features/special-characters.html).\n\n\u003c/details\u003e\n\n#### `wproofreader(version: nil, cdn: nil, compress: true, **config)` method\n\n\u003cdetails\u003e\n  \u003csummary\u003eConfigure WProofreader plugin\u003c/summary\u003e\n\n\u003cbr /\u003e\n\nDefines the WProofreader plugin to be included in the editor. The example below shows how to include the WProofreader plugin:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  wproofreader serviceId: 'your-service-ID',\n               srcUrl: 'https://svc.webspellchecker.net/spellcheck31/wscbundle/wscbundle.js'\nend\n```\n\nThe `version` keyword argument allows you to specify the version of the WProofreader plugin. The `cdn` keyword argument allows you to specify the CDN to be used for the WProofreader plugin.\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  wproofreader version: '2.0.0',\n               cdn: 'https://cdn.jsdelivr.net/npm/@ckeditor/ckeditor5-wproofreader@2.0.0/dist',\n               serviceId: 'your-service-ID',\n               srcUrl: 'https://svc.webspellchecker.net/spellcheck31/wscbundle/wscbundle.js'\nend\n```\n\nIf no `language` is set, the plugin will use the default language of the editor. If you want to set the language of the WProofreader plugin, you can use the `language` keyword argument:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  wproofreader serviceId: 'your-service-ID',\n               srcUrl: 'https://svc.webspellchecker.net/spellcheck31/wscbundle/wscbundle.js',\n               language: :en_US,\n               localization: :pl\nend\n```\n\nFor more info about the WProofreader plugin, check the [official documentation](https://ckeditor.com/docs/ckeditor5/latest/features/spelling-and-grammar-checking.html).\n\n\u003c/details\u003e\n\n#### `custom_translations(lang_code = nil, translations = {}, compress: true)` method\n\n\u003cdetails\u003e\n  \u003csummary\u003eDefine custom translations for CKEditor components and UI\u003c/summary\u003e\n\n\u003cbr /\u003e\n\nAllows setting custom translations for editor components, UI elements, and headings. The translations are applied globally since they override the global translation object.\n\n\u003e [!NOTE]\n\u003e This helper allows overriding builtin translations of the editor, but translations are overridden globally, as the CKEditor 5 uses a single translation object for all instances of the editor. It's recommended to use the `ckeditor5_translation_ref` helper to reference the translations in the configuration.\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  custom_translations :en, {\n    'Heading 1': 'Your custom translation value'\n  }\n\n  configure :heading, {\n    options: [\n      { model: 'heading1', title: ckeditor5_translation_ref('Heading 1') },\n      # ...\n    ]\n  }\nend\n```\n\n\u003c/details\u003e\n\n#### `compression(enabled: true)` method\n\n\u003cdetails\u003e\n  \u003csummary\u003eEnable or disable compression of the inline plugins or patches\u003c/summary\u003e\n\n\u003cbr /\u003e\n\nDefines whether the inline plugins should be compressed. It **must** be called before the `inline_plugin` and `version` methods. The example below shows how to disable compression:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  compression enabled: false\n\n  # ... other configuration\nend\n```\n\n:warning: Compression is enabled by default, and it's recommended to keep it enabled for production environments. It reduces the size of the inline plugins and patches, which improves the loading time of the editor.\nIf you want to disable compression for a specific plugin, you can pass the `compress: false` keyword argument to the `inline_plugin` method:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  inline_plugin :MyCustomPlugin, plugin_code, compress: false\nend\n```\n\n\u003c/details\u003e\n\n### Controller / View helpers 📦\n\n#### `ckeditor5_translation_ref(key)` method\n\n\u003cdetails\u003e\n  \u003csummary\u003eDefines a reference to a CKEditor 5 translation\u003c/summary\u003e\n\n\u003cbr /\u003e\n\nAllows you to reference CKEditor 5 translations in the configuration. It's particularly useful when you want to use custom translations in the editor configuration.\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  custom_translations :en, {\n    'Heading 1': 'Your custom translation value'\n  }\n\n  configure :heading, {\n    options: [\n      { model: 'heading1', title: ckeditor5_translation_ref('Heading 1') },\n      # ...\n    ]\n  }\nend\n```\n\n\u003c/details\u003e\n\n#### `ckeditor5_element_ref(selector)` method\n\n\u003cdetails\u003e\n  \u003csummary\u003eDefines a reference to a CKEditor 5 element.\u003c/summary\u003e\n\n\u003cbr /\u003e\n\nIn other words, it allows you to reference DOM elements that will be used by the editor's features. It's particularly useful for features that need to check element presence or operate on specific DOM elements. The primary example is the `presence list` feature that requires a reference to the element that will be used to display the list.\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  configure :yourPlugin, {\n      element: ckeditor5_element_ref(\"body\")\n  }\nend\n```\n\u003c/details\u003e\n\n#### `ckeditor5_preset(name = nil, \u0026block)` method\n\n\u003cdetails\u003e\n  \u003csummary\u003eThe `ckeditor5_preset` method allows you to define a custom preset in your application controller.\u003c/summary\u003e\n\n\u003cbr /\u003e\n\nIt may be useful when you want to define a preset based on the current user or request.\n\n```rb\n# app/controllers/application_controller.rb\n\nclass ApplicationController \u003c ActionController::Base\n  def show\n    @preset = ckeditor5_preset do\n      version '47.1.0'\n\n      toolbar :sourceEditing, :|, :bold, :italic, :underline, :strikethrough,\n              :subscript, :superscript, :removeFormat, :|, :bulletedList, :numberedList,\n              :fontFamily, :fontSize, :|, :link, :anchor, :|,\n              :fontColor, :fontBackgroundColor\n\n      plugins :Essentials, :Paragraph, :Bold, :Italic, :Underline, :Strikethrough,\n              :Subscript, :Superscript, :RemoveFormat, :List, :Link, :Font,\n              :FontFamily, :FontSize, :FontColor, :FontBackgroundColor, :SourceEditing, :Essentials, :Paragraph\n    end\n  end\nend\n```\n\nIn order to use the preset in the view, you can pass it to the `ckeditor5_assets` helper method:\n\n```erb\n\u003c!-- app/views/demos/index.html.erb --\u003e\n\n\u003c% content_for :head do %\u003e\n  \u003c%= ckeditor5_assets preset: @preset %\u003e\n\u003c% end %\u003e\n\n\u003c%= ckeditor5_editor %\u003e\n```\n\nIf you want to override the preset defined in the initializer, you can search for the preset by name and then override it (it'll create copy of the preset):\n\n```rb\n# app/controllers/application_controller.rb\n\nclass ApplicationController \u003c ActionController::Base\n  def show\n    @preset = ckeditor5_preset(:default).override do\n      version '47.1.0'\n\n      toolbar :sourceEditing, :|, :bold, :italic, :underline, :strikethrough,\n              :subscript, :superscript, :removeFormat, :|, :bulletedList, :numberedList,\n              :fontFamily, :fontSize, :|, :link, :anchor, :|,\n              :fontColor, :fontBackgroundColor\n\n      plugins :Essentials, :Paragraph, :Bold, :Italic, :Underline, :Strikethrough,\n              :Subscript, :Superscript, :RemoveFormat, :List, :Link, :Font,\n              :FontFamily, :FontSize, :FontColor, :FontBackgroundColor, :SourceEditing, :Essentials, :Paragraph\n    end\n  end\nend\n```\n\n\u003c/details\u003e\n\n## Including CKEditor 5 assets 📦\n\nTo include CKEditor 5 assets in your application, you can use the `ckeditor5_assets` helper method. This method takes the version of CKEditor 5 as an argument and includes the necessary resources of the editor. Depending on the specified configuration, it includes the JS and CSS assets from the official CKEditor 5 CDN or one of the popular CDNs.\n\nKeep in mind that you need to include the helper result in the `head` section of your layout. In examples below, we use `content_for` helper to include the assets in the `head` section of the view.\n\n### Format 📝\n\n#### Using default preset\n\nThe example below users the default preset defined [here](https://github.com/Mati365/ckeditor5-rails/blob/main/lib/ckeditor5/rails/presets/manager.rb).\n\n```erb\n\u003c!-- app/views/demos/index.html.erb --\u003e\n\n\u003c% content_for :head do %\u003e\n  \u003c%= ckeditor5_assets %\u003e\n\u003c% end %\u003e\n```\n\nIf you want to fetch some additional translations, you can extend your initializer with the following configuration:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... rest of the configuration\n\n  translations :pl, :es\nend\n```\n\n#### Custom preset\n\nTo specify a custom preset, you need to pass the `preset` keyword argument with the name of the preset. The example below shows how to include the assets for the custom preset:\n\n```erb\n\u003c!-- app/views/demos/index.html.erb --\u003e\n\n\u003c% content_for :head do %\u003e\n  \u003c%= ckeditor5_assets preset: :custom %\u003e\n\u003c% end %\u003e\n\n\u003c%-# This editor will use `custom` preset defined in `ckeditor5_assets` above %\u003e\n\u003c%= ckeditor5_editor %\u003e\n```\n\nIn order to define such preset, you can use the following configuration:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... rest of the configuration\n\n  presets.define :custom do\n    # ... your preset configuration\n\n    translations :pl, :es\n  end\nend\n```\n\n:warning: Keep in mind that all `ckeditor5_editor` helpers will use the configuration from the preset defined in the `ckeditor5_assets`. If you want to use a different preset for a specific editor, you can pass the `preset` keyword argument to the `ckeditor5_editor` helper.\n\n```erb\n\u003c!-- app/views/demos/index.html.erb --\u003e\n\n\u003c% content_for :head do %\u003e\n  \u003c%= ckeditor5_assets preset: :custom %\u003e\n\u003c% end %\u003e\n\n\u003c%= ckeditor5_editor preset: :default %\u003e\n```\n\n#### Inline preset definition\n\nIt's possible to define the preset directly in the `ckeditor5_assets` helper method. It allows you to dynamically specify version, cdn provider or even translations in the view. The example below inherits the default preset and adds Polish translations and other options:\n\n```erb\n\u003c!-- app/views/demos/index.html.erb --\u003e\n\n\u003c% content_for :head do %\u003e\n  \u003c%= ckeditor5_assets version: '43.3.0', cdn: :jsdelivr, translations: [:pl], license_key: '\u003cYOUR KEY\u003e OR GPL' %\u003e\n\u003c% end %\u003e\n```\n\n### Lazy loading 🚀\n\n\u003cdetails\u003e\n  \u003csummary\u003eExpand to show more information about lazy loading\u003c/summary\u003e\n\nAll JS assets defined by the `ckeditor5_assets` helper method are loaded **asynchronously**. It means that the assets are loaded in the background without blocking the rendering of the page. However, the CSS assets are loaded **synchronously** to prevent the flash of unstyled content and ensure that the editor is styled correctly.\n\nIt has been achieved by using web components, together with import maps, which are supported by modern browsers. The web components are used to define the editor and its plugins, while the import maps are used to define the dependencies between the assets.\n\n#### `ckeditor5_lazy_javascript_tags` helper\n\n**This method is slow as content is being loaded on the fly on the client side. Use it only when necessary.**\n\nIf you want to include the CKEditor 5 JavaScripts and Stylesheets when the editor is being appended to the DOM using Turbolinks, Stimulus, or other JavaScript frameworks, you can use the `ckeditor5_lazy_javascript_tags` helper method.\n\nThis method does not preload the assets, and it's appending web component that loads the assets when the editor is being appended to the DOM. It's useful when turbolinks frame is being replaced or when the editor is being appended to the DOM dynamically.\n\nThe example below shows how to include the CKEditor 5 assets lazily:\n\n```erb\n\u003c!-- app/views/demos/index.html.erb --\u003e\n\n\u003c% content_for :head do %\u003e\n  \u003c%= ckeditor5_lazy_javascript_tags %\u003e\n\u003c% end %\u003e\n\n\u003c%= turbo_frame_tag 'editor' do %\u003e\n  \u003c%= ckeditor5_editor %\u003e\n\u003c% end %\u003e\n```\n\n⚠️ Keep in mind that the `ckeditor5_lazy_javascript_tags` helper method should be included in the `head` section of the layout and it does not create controller context for the editors. In other words, you have to specify `preset` every time you use `ckeditor5_editor` helper (in `ckeditor5_assets` it's not necessary, as it's inherited by all editors).\n\nIf you want to keep inheritance of the presets and enforce integration to inject CKEditor 5 files on the fly, you can use the `lazy` keyword argument in the `ckeditor5_assets` helper method:\n\n```erb\n\u003c!-- app/views/demos/index.html.erb --\u003e\n\n\u003c% content_for :head do %\u003e\n  \u003c%= ckeditor5_assets preset: :custom, lazy: true %\u003e\n\u003c% end %\u003e\n\n\u003c!-- This time preset will be inherited but stylesheets and js files will be injected on the client side. --\u003e\n\u003c%= ckeditor5_editor %\u003e\n```\n\n\u003c/details\u003e\n\n### GPL usage 🆓\n\nIf you want to use CKEditor 5 under the GPL license, you can include the assets using the `ckeditor5_assets` without passing any arguments. It'll include the necessary assets for the GPL license from one of the most popular CDNs. In our scenario, we use the `jsdelivr` CDN which is the default one.\n\nExample:\n\n```erb\n\u003c!-- app/views/demos/index.html.erb --\u003e\n\n\u003c% content_for :head do %\u003e\n  \u003c%= ckeditor5_assets %\u003e\n\u003c% end %\u003e\n```\n\nIn that scenario it's recommended to add `gpl` method to the initializer along with the version:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  gpl\n  version '47.1.0'\nend\n```\n\nIn order to use `unpkg` CDN, you can extend your initializer with the following configuration:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... rest of the configuration\n\n  cdn :unpkg\nend\n```\n\nHowever, you can also specify the CDN directly in the view:\n\n```erb\n\u003c!-- app/views/demos/index.html.erb --\u003e\n\n\u003c% content_for :head do %\u003e\n  \u003c%= ckeditor5_assets cdn: :unpkg %\u003e\n\u003c% end %\u003e\n```\n\nor using helper function:\n\n```erb\n\u003c!-- app/views/demos/index.html.erb --\u003e\n\n\u003c% content_for :head do %\u003e\n  \u003c%= ckeditor5_jsdelivr_assets %\u003e\n\u003c% end %\u003e\n```\n\n### Commercial usage 💰\n\nIf you want to use CKEditor 5 under a commercial license, you have to specify license key. It can be done in the initializer:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  license_key 'your-license-key'\nend\n```\n\n```erb\n\u003c!-- app/views/demos/index.html.erb --\u003e\n\n\u003c% content_for :head do %\u003e\n  \u003c%= ckeditor5_assets %\u003e\n\u003c% end %\u003e\n```\n\nor directly in the view:\n\n```erb\n\u003c!-- app/views/demos/index.html.erb --\u003e\n\n\u003c% content_for :head do %\u003e\n  \u003c%= ckeditor5_assets license_key: 'your-license-key' %\u003e\n\u003c% end %\u003e\n```\n\nIn this scenario, the assets are included from the official CKEditor 5 CDN which is more reliable and provides better performance, especially for commercial usage.\n\n## Editor placement 🏗️\n\nThe `ckeditor5_editor` helper renders CKEditor 5 instances in your views. Before using it, ensure you've included the necessary assets in your page's head section otherwise the editor won't work as there are no CKEditor 5 JavaScript and CSS files loaded.\n\n### Setting Initial Content 📝\n\nYou can set the initial content of the editor using the `initial_data` keyword argument or by passing the content directly to the `ckeditor5_editor` helper block.\n\nThe example below shows how to set the initial content of the editor using the `initial_data` and `language` keyword arguments:\n\n```erb\n\u003c!-- app/views/demos/index.html.erb --\u003e\n\n\u003c%= ckeditor5_editor initial_data: \"\u003cp\u003eInitial content\u003c/p\u003e\" %\u003e\n```\n\nThe example below shows how to set the initial content of the editor using the `ckeditor5_editor` helper block.\n\n```erb\n\u003c!-- app/views/demos/index.html.erb --\u003e\n\n\u003c%= ckeditor5_editor do %\u003e\n  \u003cp\u003eInitial content\u003c/p\u003e\n\u003c% end %\u003e\n```\n\n### Watchdog 🐕\n\nCKEditor 5 uses a watchdog utility to protect you from data loss in case the editor crashes. It saves your content just before the crash and creates a new instance of the editor with your content intact. It's enabled by default in the gem.\n\nIf you want to disable the watchdog, you can pass the `watchdog` keyword argument with the value `false`:\n\n```erb\n\u003c!-- app/views/demos/index.html.erb --\u003e\n\n\u003c%= ckeditor5_editor watchdog: false %\u003e\n```\n\n### Classic editor 📝\n\nThe classic editor is the most common type of editor. It provides a toolbar with various formatting options like bold, italic, underline, and link.\n\nIt looks like this:\n\n![CKEditor 5 Classic Editor in Ruby on Rails application with Menubar](docs/classic-editor-with-toolbar.png)\n\nThe example below shows how to include the classic editor in your view:\n\n```erb\n\u003c!-- app/views/demos/index.html.erb --\u003e\n\n\u003c% content_for :head do %\u003e\n  \u003c%= ckeditor5_assets %\u003e\n\u003c% end %\u003e\n\n\u003c%= ckeditor5_editor style: 'width: 600px' %\u003e\n```\n\nYou can pass the `style` keyword argument to the `ckeditor5_editor` helper to define the editor's style. The example above shows how to set the width of the editor to `600px`. However you can pass any HTML attribute you want, such as `class`, `id`, `data-*`, etc.\n\nWhile example above uses predefined `:default` preset, you can use your custom presets by passing the `preset` keyword argument:\n\n```erb\n\u003c!-- app/views/demos/index.html.erb --\u003e\n\n\u003c% content_for :head do %\u003e\n  \u003c%= ckeditor5_assets %\u003e\n\u003c% end %\u003e\n\n\u003c%= ckeditor5_editor preset: :custom, style: 'width: 600px' %\u003e\n```\n\nIf your configuration is even more complex, you can pass the `config` and `type` arguments with the configuration hash:\n\n```erb\n\u003c!-- app/views/demos/index.html.erb --\u003e\n\n\u003c% content_for :head do %\u003e\n  \u003c%= ckeditor5_assets %\u003e\n\u003c% end %\u003e\n\n\u003c%= ckeditor5_editor type: :classic, config: { plugins: [:Bold, :Italic], toolbar: [:Bold, :Italic] }, style: 'width: 600px' %\u003e\n```\n\nIf you want to override the configuration of the editor specified in default or custom preset, you can pass the `extra_config` keyword argument with the configuration hash:\n\n```erb\n\u003c!-- app/views/demos/index.html.erb --\u003e\n\n\u003c% content_for :head do %\u003e\n  \u003c!-- You can override default preset in assets helper too. --\u003e\n  \u003c%= ckeditor5_assets translations: [:pl] %\u003e\n\u003c% end %\u003e\n\n\u003c%= ckeditor5_editor extra_config: { toolbar: [:Bold, :Italic] }, style: 'width: 600px' %\u003e\n```\n\nIt's possible to define the height of the editor by passing the `editable_height` keyword argument with the value in pixels:\n\n```erb\n\u003c!-- app/views/demos/index.html.erb --\u003e\n\n\u003c% content_for :head do %\u003e\n  \u003c%= ckeditor5_assets %\u003e\n\u003c% end %\u003e\n\n\u003c%= ckeditor5_editor editable_height: 300 %\u003e\n```\n\n### Multiroot editor 🌳\n\nThe multiroot editor allows you to create an editor with multiple editable areas. It's useful when you want to create a CMS with multiple editable areas on a single page.\n\n- `ckeditor5_editor`: Defines the editor instance.\n- `ckeditor5_editable`: Defines the editable areas within the editor.\n- `ckeditor5_toolbar`: Defines the toolbar for the editor.\n\n![CKEditor 5 Multiroot Editor in Ruby on Rails application](docs/multiroot-editor.png)\n\nIf you want to use a multiroot editor, you can pass the `type` keyword argument with the value `:multiroot`:\n\n```erb\n\u003c!-- app/views/demos/index.html.erb --\u003e\n\n\u003c% content_for :head do %\u003e\n  \u003c%= ckeditor5_assets %\u003e\n\u003c% end %\u003e\n\n\u003c%= ckeditor5_editor type: :multiroot, style: 'width: 600px' do %\u003e\n  \u003c%= ckeditor5_toolbar %\u003e\n  \u003cbr\u003e\n  \u003c%= ckeditor5_editable 'toolbar', style: 'border: 1px solid var(--ck-color-base-border);' do %\u003e\n    This is a toolbar editable\n  \u003c% end %\u003e\n  \u003cbr\u003e\n  \u003c%= ckeditor5_editable 'content', style: 'border: 1px solid var(--ck-color-base-border)' %\u003e\n  \u003cbr\u003e\n\u003c% end %\u003e\n```\n\nRoots can be defined later to the editor by simply adding new elements rendered by `ckeditor5_editable` helper.\n\n### Inline editor 📝\n\nInline editor allows you to create an editor that can be placed inside any element. Keep in mind that inline editor does not work with `textarea` elements so it might be not suitable for all use cases.\n\n![CKEditor 5 Inline Editor in Ruby on Rails application](docs/inline-editor.png)\n\nIf you want to use an inline editor, you can pass the `type` keyword argument with the value `:inline`:\n\n```erb\n\u003c!-- app/views/demos/index.html.erb --\u003e\n\n\u003c% content_for :head do %\u003e\n  \u003c%= ckeditor5_assets %\u003e\n\u003c% end %\u003e\n\n\u003c%= ckeditor5_editor type: :inline, style: 'width: 600px' %\u003e\n```\n\n### Balloon editor 🎈\n\nBalloon editor is a floating toolbar editor that provides a minimalistic interface. It's useful when you want to create a simple editor with a floating toolbar.\n\n![CKEditor 5 Balloon Editor in Ruby on Rails application](docs/balloon-editor.png)\n\nIf you want to use a balloon editor, you can pass the `type` keyword argument with the value `:balloon`:\n\n```erb\n\u003c!-- app/views/demos/index.html.erb --\u003e\n\n\u003c% content_for :head do %\u003e\n  \u003c%= ckeditor5_assets %\u003e\n\u003c% end %\u003e\n\n\u003c%= ckeditor5_editor type: :balloon, style: 'width: 600px' %\u003e\n```\n\n### Decoupled editor 🌐\n\nDecoupled editor is a variant of classic editor that allows you to separate the editor from the content area. It's useful when you want to create a custom interface with the editor.\n\n![CKEditor 5 Decoupled Editor in Ruby on Rails application](docs/decoupled-editor.png)\n\nIf you want to use a decoupled editor, you can pass the `type` keyword argument with the value `:decoupled`:\n\n```erb\n\u003c!-- app/views/demos/index.html.erb --\u003e\n\n\u003c% content_for :head do %\u003e\n  \u003c%= ckeditor5_assets %\u003e\n\u003c% end %\u003e\n\n\u003c%= ckeditor5_editor type: :decoupled, style: 'width: 600px' do %\u003e\n  \u003cdiv class=\"menubar-container\"\u003e\n    \u003c%= ckeditor5_menubar %\u003e\n  \u003c/div\u003e\n\n  \u003cdiv class=\"toolbar-container\"\u003e\n    \u003c%= ckeditor5_toolbar %\u003e\n  \u003c/div\u003e\n\n  \u003cdiv class=\"editable-container\"\u003e\n    \u003c%= ckeditor5_editable %\u003e\n  \u003c/div\u003e\n\u003c% end %\u003e\n```\n\n## Using Context 📦\n\nContext CKEditor 5 is a feature that allows multiple editor instances to share a common configuration and state. This is particularly useful in collaborative environments where multiple users are editing different parts of the same document simultaneously. By using a shared context, all editor instances can synchronize their configurations, plugins, and other settings, ensuring a consistent editing experience across all users.\n\n![CKEditor 5 Context](docs/context.png)\n\n### Using Context in CKEditor 5 🔄\n\nFormat of the `ckeditor5_context` helper:\n\n```erb\n\u003c!-- app/views/demos/index.html.erb --\u003e\n\n\u003c%= ckeditor5_context @context_preset do %\u003e\n  \u003c%= ckeditor5_editor %\u003e\n  \u003c%= ckeditor5_editor %\u003e\n\u003c% end %\u003e\n```\n\nThe `ckeditor5_context` helper takes the context preset as an argument and renders the editor instances within the context. The context preset defines the shared configuration and state of the editor instances. It should be defined somewhere in controller.\n\n### Example usage of `ckeditor5_context` helper 📝\n\nIn your view:\n\n```erb\n\u003c!-- app/views/demos/index.html.erb --\u003e\n\n\u003c% content_for :head do %\u003e\n  \u003c%= ckeditor5_assets preset: :ultrabasic %\u003e\n\u003c% end %\u003e\n\n\u003c%= ckeditor5_context @context_preset do %\u003e\n  \u003c%= ckeditor5_editor initial_data: 'Hello World' %\u003e\n\n  \u003cbr\u003e\n\n  \u003c%= ckeditor5_editor initial_data: 'Hello World 2' %\u003e\n\u003c% end %\u003e\n```\n\nIn your controller:\n\n```rb\n# app/controllers/demos_controller.rb\n\nclass DemosController \u003c ApplicationController\n  def index\n    @context_preset = ckeditor5_context_preset do\n      # Syntax is identical to the `toolbar` method of the preset configuration.\n      toolbar :bold, :italic\n\n      # It's possible to define plugins. Syntax is identical to the `plugins` method of the preset configuration.\n      # Example:\n      # plugin :Bold\n      # inline_plugin :MyCustomPlugin, '...'\n    end\n  end\nend\n```\n\nIt's possible to omit the preset argument, in that case the empty preset will be used.\n\n```erb\n\u003c!-- app/views/demos/index.html.erb --\u003e\n\n\u003c%= ckeditor5_context do %\u003e\n  \u003c%= ckeditor5_editor %\u003e\n  \u003c%= ckeditor5_editor %\u003e\n\u003c% end %\u003e\n```\n\nSee demo for more details.\n\n## How to access editor instance? 🤔\n\nYou can access the editor instance using plain HTML and JavaScript, as CKEditor 5 is a web component with defined `instance`, `instancePromise` and `editables` properties.\n\nFor example:\n\n```erb\n\u003c!-- app/views/demos/index.html.erb --\u003e\n\n\u003c% content_for :head do %\u003e\n  \u003c%= ckeditor5_assets %\u003e\n\u003c% end %\u003e\n\n\u003c%= ckeditor5_editor style: 'width: 600px', id: 'editor' %\u003e\n```\n\n⚠️ Direct access of `instance` property of the web component. Keep in mind it's unsafe and may cause issues if the editor is not loaded yet.\n\n```js\ndocument.getElementById('editor').instance;\n```\n\n👌 Accessing the editor instance using `instancePromise` property. It's a promise that resolves to the editor instance when the editor is ready.\n\n```js\ndocument.getElementById('editor').instancePromise.then((editor) =\u003e {\n  console.log(editor);\n});\n```\n\n✅ Accessing the editor through the `runAfterEditorReady` helper method. It's a safe way to access the editor instance when the editor is ready.\n\n```js\ndocument.getElementById('editor').runAfterEditorReady((editor) =\u003e {\n  console.log(editor);\n});\n```\n\n## Common Tasks and Solutions 💡\n\nThis section covers frequent questions and scenarios when working with CKEditor 5 in Rails applications.\n\n### Setting Editor Language 🌐\n\nBy default, CKEditor 5 uses the language specified in your `I18n.locale` configuration. However, you can override the language of the editor by passing the `language` keyword in few places.\n\n#### Setting the language in the assets helper\n\nLanguage specified here will be used for all editor instances on the page.\n\n```erb\n\u003c!-- app/views/demos/index.html.erb --\u003e\n\n\u003c% content_for :head do %\u003e\n  \u003c%= ckeditor5_assets language: :pl %\u003e\n\u003c% end %\u003e\n\n\u003c%= ckeditor5_editor %\u003e\n```\n\n#### Setting the language in the initializer\n\nLanguage specified here will be used for all editor instances in your application.\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # Optional, it load multiple translation packs: translations :pl, :es\n  language :pl\nend\n```\n\n#### Setting the language on the editor level\n\nLanguage specified here will be used only for this editor instance. Keep in mind that you have to load the translation pack in the assets helper using the `translations` initializer method.\n\n```erb\n\u003c!-- app/views/demos/index.html.erb --\u003e\n\n\u003c%= ckeditor5_editor language: :pl %\u003e\n```\n\n#### Preloading multiple translation packs\n\nYou can preload multiple translation packs in the initializer using the `translations` method:\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  translations :pl, :es\nend\n```\n\n### Spell and Grammar Checking 📝\n\nCKEditor 5 provides a spell and grammar checking feature through the WProofreader plugin. You can enable this feature by configuring the WProofreader plugin in the initializer.\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  wproofreader serviceId: 'your-service-ID',\n               srcUrl: 'https://svc.webspellchecker.net/spellcheck31/wscbundle/wscbundle.js'\nend\n```\n\nSee [`wproofreader(version: nil, cdn: nil, **config)` method](#wproofreaderversion-nil-cdn-nil-config-method) for more information about the WProofreader plugin configuration.\n\nSee the [official documentation](https://ckeditor.com/docs/ckeditor5/latest/features/spelling-and-grammar-checking.html) for more information about the WProofreader plugin.\n\n### Integrating with Forms 📋\n\nYou can integrate CKEditor 5 with Rails form builders like `form_for` or `simple_form`. The example below shows how to integrate CKEditor 5 with a Rails form using the `form_for` helper:\n\n#### Rails form builder integration\n\n```erb\n\u003c!-- app/views/demos/index.html.erb --\u003e\n\n\u003c%= form_for @post do |f| %\u003e\n  \u003c%= f.label :content %\u003e\n  \u003c%= f.ckeditor5 :content, required: true, style: 'width: 700px', initial_data: 'Hello World!' %\u003e\n\u003c% end %\u003e\n```\n\n#### Simple form integration\n\n```erb\n\u003c!-- app/views/demos/index.html.erb --\u003e\n\n\u003c%= simple_form_for :demo, url: '/demos', html: { novalidate: false } do |f| %\u003e\n  \u003cdiv class=\"form-group\"\u003e\n    \u003c%= f.input :content, as: :ckeditor5, initial_data: 'Hello, World 12!', input_html: { style: 'width: 600px' }, required: true %\u003e\n  \u003c/div\u003e\n\n  \u003cdiv class=\"form-group mt-3\"\u003e\n    \u003c%= f.button :submit, 'Save', class: 'btn btn-primary' %\u003e\n  \u003c/div\u003e\n\u003c% end %\u003e\n```\n\n### Integration with Turbolinks 🚀\n\nIf you're using Turbolinks in your Rails application, you may need to load CKEditor 5 in embeds that are loaded dynamically and not on the initial page load. In this case, you can use the `ckeditor5_lazy_javascript_tags` helper method to load CKEditor 5 assets when the editor is appended to the DOM. This method is useful when you're using Turbolinks or Stimulus to load CKEditor 5 dynamically.\n\nYour view should look like this:\n\n```erb\n\u003c!-- app/views/demos/index.html.erb --\u003e\n\n\u003c% content_for :head do %\u003e\n  \u003c%= ckeditor5_lazy_javascript_tags %\u003e\n\u003c% end %\u003e\n```\n\nYour ajax partial should look like this:\n\n```erb\n\u003c!-- app/views/demos/_form.html.erb --\u003e\n\n\u003c!-- Presets and other configuration as usual --\u003e\n\u003c%= ckeditor5_editor %\u003e\n```\n\nThis method does not preload the assets, and it's appending web component that loads the assets when the editor is being appended to the DOM. Please see the [Lazy Loading](#lazy-loading) section for more information and [demos](https://github.com/Mati365/ckeditor5-rails/blob/main/sandbox/app/views/demos/form_ajax.slim) on how to use this method.\n\n### Custom Styling 🎨\n\nYou can pass the `style`, `class` and `id` keyword arguments to the `ckeditor5_editor` helper to define the styling of the editor. The example below shows how to set the height, margin, and CSS class of the editor:\n\n```erb\n\u003c!-- app/views/demos/index.html.erb --\u003e\n\n\u003c%= ckeditor5_editor style: 'height: 400px; margin: 20px;', class: 'your_css_class', id: 'your_id' %\u003e\n```\n\n### Custom plugins 🧩\n\nYou can create custom plugins for CKEditor 5 using the `inline_plugin` method. It allows you to define a custom class or function inside your preset configuration.\n\nThe example below shows how to define a custom plugin that allows toggling the highlight of the selected text:\n\n![CKEditor 5 Custom Highlight Plugin in Ruby on Rails application](docs/custom-highlight-plugin.png)\n\n```rb\n# config/initializers/ckeditor5.rb\n\nCKEditor5::Rails.configure do\n  # ... other configuration\n\n  # 1. You can also use \"window_name\" option to import plugin from window object:\n\n  # plugin :MyPlugin, window_name: 'MyPlugin'\n\n  # 2. Create JavaScript file in app/javascript/custom_plugins/highlight.js,\n  #    add it to import map and then load it in initializer:\n\n  # plugin :MyCustomPlugin, import_name: 'my-custom-plugin'\n\n  # 3 Create JavaScript file in app/javascript/custom_plugins/highlight.js\n  #   and then load it in initializer:\n\n  # In Ruby initializer you can also load plugin code directly from file:\n  inline_plugin :MyCustomPlugin, File.read(\n    Rails.root.join('app/javascript/custom_plugins/highlight.js')\n  )\n\n  # 4. Or even define it inline:\n  # inline_plugin :MyCustomPlugin,  \u003c\u003c~JS\n  #    const { Plugin } = await import( 'ckeditor5' );\n  #\n  #    return class MyCustomPlugin extends Plugin {\n  #      // ...\n  #    }\n  # JS\n\n  # Add item to beginning of the toolbar.\n  toolbar do\n    prepend :highlight\n  end\nend\n```\n\n\u003cdetails\u003e\n  \u003csummary\u003eExample of Custom Highlight Plugin 🎨\u003c/summary\u003e\n\n```js\n// app/javascript/custom_plugins/highlight.js\nconst { Plugin, Command, ButtonView } = await import('ckeditor5');\n\nreturn class MyCustomPlugin extends Plugin {\n  static get pluginName() {\n    return 'MyCustomPlugin';\n  }\n\n  init() {\n    const editor = this.editor;\n\n    // Define schema for highlight attribute\n    editor.model.schema.extend('$text', { allowAttributes: 'highlight' });\n\n    // Define conversion between model and view\n    editor.conversion.attributeToElement({\n      model: 'highlight',\n      view: {\n        name: 'span',\n        styles: {\n          'background-color': 'yellow'\n        }\n      }\n    });\n\n    // Create command that handles highlighting logic\n    // Command pattern is used to encapsulate all the logic related to executing an action\n    const command = new HighlightCommand(editor);\n\n    // Register command in editor\n    editor.commands.add('highlight', command);\n\n    // Add UI button\n    editor.ui.componentFactory.add('highlight', locale =\u003e {\n      const view = new ButtonView(locale);\n\n      // Bind button state to command state using bind method\n      // bind() allows to sync button state with command state automatically\n      view.bind('isOn').to(command, 'value');\n\n      view.set({\n        label: 'Highlight',\n        withText: true,\n        tooltip: true\n      });\n\n      view.on('execute', () =\u003e {\n        editor.execute('highlight');\n        editor.editing.view.focus();\n      });\n\n      return view;\n    });\n  }\n}\n\n// Command class that handles the highlight feature\n// isEnabled property determines if command can be executed\nclass HighlightCommand extends Command {\n  execute() {\n    const model = this.editor.model;\n    const selection = model.document.selection;\n\n    model.change(writer =\u003e {\n      const ranges = model.schema.getValidRanges(selection.getRanges(), 'highlight');\n\n      for (const range of ranges) {\n        if (this.value) {\n          writer.removeAttribute('highlight', range);\n        } else {\n          writer.setAttribute('highlight', true, range);\n        }\n      }\n    });\n  }\n\n  refresh() {\n    const model = this.editor.model;\n    const selection = model.document.selection;\n    const isAllowed = model.schema.checkAttributeInSelection(selection, 'highlight');\n\n    // Set if command is enabled based on schema\n    this.isEnabled = isAllowed;\n    this.value = this.#isHighlightedNodeSelected();\n  }\n\n  // Check if the highlighted node is selected.\n  #isHighlightedNodeSelected() {\n    const { model } = this.editor\n    const { schema } = model\n    const selection = model.document.selection\n\n    if (selection.isCollapsed) {\n      return selection.hasAttribute('highlight')\n    }\n\n    return selection.getRanges().some(range =\u003e\n      Array\n        .from(range.getItems())\n        .some(item =\u003e\n          schema.checkAttribute(item, 'highlight') \u0026\u0026\n          item.hasAttribute('highlight')\n        )\n    );\n  }\n}\n```\n\n\u003c/details\u003e\n\n### Content Security Policy (CSP) 🛡️\n\nIf you're using a Content Security Policy (CSP) in your Rails application, you may need to adjust it to allow CKEditor 5 to work correctly. CKEditor 5 uses inline scripts and styles to render the editor, so you need to allow them in your CSP configuration. The example below shows how to configure the CSP to allow CKEditor 5 to work correctly:\n\n```rb\n# config/initializers/content_security_policy.rb\n\nRails.application.configure do\n  config.content_security_policy do |policy|\n    policy.default_src :self, :https\n    policy.font_src :self, :https, :data\n    policy.img_src :self, :https, :data\n    policy.object_src :none\n    policy.script_src \"'strict-dynamic'\"\n    policy.style_src :self, :https\n    policy.style_src_elem :self, :https, :unsafe_inline\n    policy.style_src_attr :self, :https, :unsafe_inline\n    policy.base_uri :self\n  end\n\n  config.content_security_policy_nonce_generator = -\u003e(_request) { SecureRandom.base64(16) }\n  config.content_security_policy_nonce_directives = %w[script-src style-src]\nend\n```\n\n## Events fired by the editor 🔊\n\nCKEditor 5 provides a set of events that you can listen to in order to react to changes in the editor. You can listen to these events using the `addEventListener` method or by defining event handlers directly in the view.\n\n### `editor-ready` event\n\nThe event is fired when the initialization of the editor is completed. You can listen to it using the `editor-ready` event.\n\n```js\ndocument.getElementById('editor').addEventListener('editor-ready', () =\u003e {\n  console.log('Editor is ready');\n});\n```\n\n### `editor-error` event\n\nThe event is fired when the initialization of the editor fails. You can listen to it using the `editor-error` event.\n\n```js\ndocument.getElementById('editor').addEventListener('editor-error', () =\u003e {\n  console.log('Editor has an error');\n});\n```\n\n### `editor-change` event\n\nThe event is fired when the content of the editor changes. You can listen to it using the `editor-change` event.\n\n```js\ndocument.getElementById('editor').addEventListener('editor-change', () =\u003e {\n  console.log('Editor content has changed');\n});\n```\n\n### Inline event handling\n\nYou can also define event handlers directly in the view using the `oneditorchange`, `oneditorerror`, and `oneditorready` attributes.\n\n```erb\n\u003c!-- app/views/demos/index.html.erb --\u003e\n\n\u003cscript type=\"text/javascript\"\u003e\n  function onEditorChange(event) {\n    // event.detail.editor, event.detail.data\n  }\n\n  function onEditorError(event) {\n    // event.detail.editor\n  }\n\n  function onEditorReady(event) {\n    // event.detail.editor\n  }\n\u003c/script\u003e\n\n\u003c%= ckeditor5_editor id: 'editor',\n    oneditorchange: 'onEditorChange',\n    oneditorerror: 'onEditorError',\n    oneditorready: 'onEditorReady'\n%\u003e\n```\n\n## Gem Development 🛠\n\nIf you want to contribute to the gem, you can clone the repository and run the following commands:\n\n```sh\ngem install bundler -v 2.5.22\nbundle install\nnpm install\nbundle exec guard -g rails\n```\n\n### Building NPM package 📦\n\nTo build the NPM package, you can run the following command:\n\n```sh\nnpm run build\n```\n\n### Running tests 🧪\n\nYou can run the tests using the following command:\n\n```sh\nbundle exec rspec\n```\n\nIf you want to watch the tests, you can use the following command:\n\n```sh\nbundle exec guard -g rspec\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-livewire](https://github.com/Mati365/ckeditor5-livewire)\n  Drop-in CKEditor 5 solution for Laravel + Livewire apps. Works great with Blade forms too. Includes JS hooks, flexible config, and easy customization.\n\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 gem 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-rails","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FMati365%2Fckeditor5-rails","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FMati365%2Fckeditor5-rails/lists"}