Project

ckeditor5

0.01
The project is in a healthy, maintained state
CKEditor 5 for Rails
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Runtime

>= 6.0, < 9.0
~> 1.0
 Project Readme

CKEditor 5 Rails Integration โœจ

License: GPL v2 Gem Version Gem Total Downloads Coverage PRs Welcome GitHub code size in bytes GitHub issues

Unofficial CKEditor 5 Ruby on Rails integration gem. Provides seamless integration of CKEditor 5 with Rails applications through web components and helper methods.

CKEditor 5 Classic Editor in Ruby on Rails application

Installation ๐Ÿ› ๏ธ

Add this line to your application's Gemfile:

gem 'ckeditor5'

In your layout:

<!-- app/views/layouts/application.html.erb -->

<!DOCTYPE html>
<html>
  <head>
    <!--
      โš ๏ธ **Important**: When using `importmap-rails`, make sure the importmap
      tags are rendered after `ckeditor5_assets` helper. In this scenario,
      content is yielded before rendering `javascript_importmap_tags`.
    -->
    <!-- javascript_importmap_tags -->
    <%= yield :head %>
  </head>
  <body>
    <%= yield %>
  </body>
</html>

In your view:

<!-- app/views/demos/index.html.erb -->

<% content_for :head do %>
  <!-- ๐Ÿ“ฆ Adds importmap with CKEditor 5 assets. -->
  <!-- ๐ŸŒ It'll automatically use your `I18n.locale` language. -->
  <%= ckeditor5_assets %>
<% end %>

<!-- ๐Ÿ–‹๏ธ CKEditor 5 might be placed using simple view helper ... -->
<%= ckeditor5_editor %>

<!-- ... or using form input helper -->

<%= form_for @post do |f| %>
  <%= f.ckeditor5 :content, required: true %>
<% end %>

(optional) Customize your config (the default config is defined here):

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ๐Ÿ”– Specify the version of editor you want.
  # โš™๏ธ Default configuration includes:
  #    ๐Ÿ“ Classic editor build
  #    ๐Ÿงฉ Essential plugins (paragraphs, basic styles)
  #    ๐ŸŽ›๏ธ Default toolbar layout
  #    ๐Ÿ“œ GPL license

  # Optionally, you can specify version of CKEditor 5 to use.
  # If it's not specified the default version specified in the gem will be used.
  # version '44.1.0'

  # Upload images to the server using the simple upload adapter, instead of Base64 encoding.
  # simple_upload_adapter

  # Specify global language for the editor.
  # It can be done here, in controller or in the view.
  # By default the `I18n.locale` is used.
  # language :pl
end

Voilร ! You have CKEditor 5 integrated with your Rails application. ๐ŸŽ‰

Try Demos! ๐ŸŽฎ โœจ

Explore various editor configurations with the interactive demo application. For additional inspiration, visit the official CKEditor 5 examples.

To run the demos locally, follow these steps:

bundle install # Install dependencies
bundle exec guard -g rails # Start the server

Open http://localhost:3000/ in a browser to start experimenting. Modify the code as needed.

For extending CKEditor's functionality, refer to the plugins directory to create custom plugins. Community contributions are welcome.

Table of Contents ๐Ÿ“š

  • CKEditor 5 Rails Integration โœจ
    • Installation ๐Ÿ› ๏ธ
    • Try Demos! ๐ŸŽฎ โœจ
    • Table of Contents ๐Ÿ“š
    • Presets ๐ŸŽจ
      • Automatic upgrades ๐Ÿ”„
      • Available Configuration Methods โš™๏ธ
        • cdn(cdn = nil, &block) method
        • version(version) method
        • automatic_upgrades(enabled: true) method
        • gpl method
        • license_key(key) method
        • premium method
        • editable_height(height) method
        • language(ui, content:) method
        • translations(*languages) method
        • ckbox method
        • type(type) method
        • toolbar(*items, should_group_when_full: true, &block) method
        • block_toolbar(*items, should_group_when_full: true, &block) method
        • balloon_toolbar(*items, should_group_when_full: true, &block) method
        • menubar(visible: true) method
        • configure(name, value) method
        • plugin(name, premium:, import_name:) method
        • plugins(*names, **kwargs) method
        • inline_plugin(name, code) method
        • external_plugin(name, script:, import_as: nil, window_name: nil, stylesheets: []) method
        • simple_upload_adapter(url) method
        • wproofreader(version: nil, cdn: nil, **config) method
      • Controller / View helpers ๐Ÿ“ฆ
        • ckeditor5_element_ref(selector) method
        • ckeditor5_preset(name = nil, &block) method
    • Including CKEditor 5 assets ๐Ÿ“ฆ
      • Format ๐Ÿ“
        • Using default preset
        • Custom preset
        • Inline preset definition
      • Lazy loading ๐Ÿš€
        • ckeditor5_lazy_javascript_tags helper
      • GPL usage ๐Ÿ†“
      • Commercial usage ๐Ÿ’ฐ
    • Editor placement ๐Ÿ—๏ธ
      • Setting Initial Content ๐Ÿ“
      • Watchdog ๐Ÿ•
      • Classic editor ๐Ÿ“
      • Multiroot editor ๐ŸŒณ
      • Inline editor ๐Ÿ“
      • Balloon editor ๐ŸŽˆ
      • Decoupled editor ๐ŸŒ
    • Using Context ๐Ÿ“ฆ
      • Using Context in CKEditor 5 ๐Ÿ”„
      • Example usage of ckeditor5_context helper ๐Ÿ“
    • How to access editor instance? ๐Ÿค”
    • Common Tasks and Solutions ๐Ÿ’ก
      • Setting Editor Language ๐ŸŒ
        • Setting the language in the assets helper
        • Setting the language in the initializer
        • Setting the language on the editor level
        • Preloading multiple translation packs
      • Spell and Grammar Checking ๐Ÿ“
      • Integrating with Forms ๐Ÿ“‹
        • Rails form builder integration
        • Simple form integration
      • Integration with Turbolinks ๐Ÿš€
      • Custom Styling ๐ŸŽจ
      • Custom plugins ๐Ÿงฉ
      • Content Security Policy (CSP) ๐Ÿ›ก๏ธ
    • Events fired by the editor ๐Ÿ”Š
      • editor-ready event
      • editor-error event
      • editor-change event
      • Inline event handling
    • Gem Development ๐Ÿ› 
      • Running tests ๐Ÿงช
    • Trademarks ๐Ÿ“œ
    • License ๐Ÿ“œ

Presets ๐ŸŽจ

Presets 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.

You 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:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # It's possible to override the default preset right in the initializer.
  version '44.1.0'

  # New presets inherit properties from the default preset defined in the initializer.
  # In this example, the custom preset inherits everything from default but disables the menubar:
  presets.define :inherited_custom
    menubar visible: false
  end

  # In order to define preset from scratch, you can use the `inherit: false` option.
  presets.define :blank_preset, inherit: false do
    version '44.1.0'

    # It tells the integration to fetch the newest security patches and bug fixes.
    # It may be disabled, but it's highly recommended to keep it enabled to avoid
    # potential security issues.
    automatic_upgrades

    gpl
    type :classic

    menubar
    toolbar :undo, :redo, :|, :heading, :|, :bold, :italic, :underline, :|,
            :link, :insertImage, :mediaEmbed, :insertTable, :blockQuote, :|,
            :bulletedList, :numberedList, :todoList, :outdent, :indent

    plugins :AccessibilityHelp, :Autoformat, :AutoImage, :Autosave,
            :BlockQuote, :Bold, :CloudServices,
            :Essentials, :Heading, :ImageBlock, :ImageCaption, :ImageInline,
            :ImageInsert, :ImageInsertViaUrl, :ImageResize, :ImageStyle,
            :ImageTextAlternative, :ImageToolbar, :ImageUpload, :Indent,
            :IndentBlock, :Italic, :Link, :LinkImage, :List, :ListProperties,
            :MediaEmbed, :Paragraph, :PasteFromOffice, :PictureEditing,
            :SelectAll, :Table, :TableCaption, :TableCellProperties,
            :TableColumnResize, :TableProperties, :TableToolbar,
            :TextTransformation, :TodoList, :Underline, :Undo, :Base64UploadAdapter

    configure :image, {
      toolbar: ['imageTextAlternative', 'imageStyle:inline', 'imageStyle:block', 'imageStyle:side']
    }
  end
end

In 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:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  presets.override :custom do
    menubar visible: false

    toolbar do
      remove :underline, :heading
    end
  end
end

You can define presets in the controller using the ckeditor5_preset helper method. See it in the section below (Controller / View helpers).

Configuration of the editor can be complex, and it's recommended to use the 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.

Automatic upgrades ๐Ÿ”„

The gem includes a feature that automatically upgrades the CKEditorย 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.

If you want to disable automatic upgrades, you can pass the enabled: false keyword argument to the automatic_upgrades method.

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  automatic_upgrades enabled: false
end

Available Configuration Methods โš™๏ธ

cdn(cdn = nil, &block) method

Configure custom CDN URL pattern or use predefined CDNs like jsdelivr or unpkg

Defines the CDN to be used for CKEditor 5 assets. The example below shows how to set the CDN to :jsdelivr:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  cdn :jsdelivr
end

It 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:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  cdn do |bundle, version, path|
    base_url = "https://cdn.jsdelivr.net/npm/#{bundle}@#{version}/dist"

    "#{base_url}/#{path.start_with?('translations/') ? '' : 'browser/'}#{path}"
  end
end

version(version) method

Set up the version of CKEditor 5 to be used by the integration

Defines the version of CKEditor 5 to be used. The example below shows how to set the version to 43.2.0:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  version '44.1.0'
end

automatic_upgrades(enabled: true) method

Enable or disable automatic security patches and bug fixes

Defines if automatic upgrades should be enabled. It's enabled for the :default preset by default. The example below shows how to disable automatic upgrades:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  automatic_upgrades enabled: false
end

It 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.

Version is checked every nth day, where n is the number of days since the last check. Currently it's 4 days.

gpl method

Defines the license of CKEditor 5. The example below shows how to set the license to GPL:

Defines the license of CKEditor 5. The example below shows how to set the license to GPL:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  gpl
end

license_key(key) method

Defines the license key of CKEditor 5. It calls `premium` method internally. The example below shows how to set the license key:

Defines the license key of CKEditor 5. It calls premium method internally. The example below shows how to set the license key:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  license_key 'your-license-key'
end

premium method

Defines if premium package should be included in JS assets. The example below shows how to add `ckeditor5-premium-features` to import maps:

Defines if premium package should be included in JS assets. The example below shows how to add ckeditor5-premium-features to import maps:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  premium
end

editable_height(height) method

Set editor height in pixels - useful for fixed-size layouts

Defines the height of the editor. The example below shows how to set the height to 300px:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  editable_height 300
end

language(ui, content:) method

Set UI and content language for the editor

Defines 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:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  language :pl
end

In order to set the language for the content, you can pass the content keyword argument:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  language :pl, content: :en
end

The 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.

translations(*languages) method

Load additional language files for the editor interface

Defines 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:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  translations :pl, :es
end

โš ๏ธ 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.

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  translations :pl
  language :pl
end

ckbox method

Configure CKBox file manager integration

Defines the CKBox plugin to be included in the editor. The example below shows how to include the CKBox plugin:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  ckbox '2.6.0', theme: :lark
end

type(type) method

Select editor type (classic, inline, balloon, decoupled, multiroot)

Defines the type of editor. Available options:

  • :classic - classic edytor
  • :inline - inline editor
  • :decoupled - decoupled editor
  • :balloon - balloon editor
  • :multiroot - editor with multiple editing areas

The example below sets the editor type to multiroot in the custom preset:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  type :multiroot
end

toolbar(*items, should_group_when_full: true, &block) method

Define toolbar items and their grouping behavior

Defines the toolbar items. You can use predefined items like :undo, :redo, :| or specify custom items. There are a few special items:

  • :_ - breakpoint
  • :| - separator

The 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.

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  toolbar :undo, :redo, :|, :heading, :|, :bold, :italic, :underline, :|,
          :link, :insertImage, :ckbox, :mediaEmbed, :insertTable, :blockQuote, :|,
          :bulletedList, :numberedList, :todoList, :outdent, :indent
end

Keep 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.

If you want to add or prepend items to the existing toolbar, you can use the block syntax:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  toolbar do
    append :selectAll, :|, :selectAll, :selectAll
    # Or prepend: prepend :selectAll, :|, :selectAll, :selectAll
  end
end

If you want to remove items from the toolbar, you can use the remove method:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  toolbar do
    remove :selectAll, :heading #, ...
  end
end

If you want to append groups of items, you can use the group method:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  toolbar do
    group :text_formatting, label: 'Text Formatting', icon: 'threeVerticalDots' do
      append :bold, :italic, :underline, :strikethrough, separator,
             :subscript, :superscript, :removeFormat
    end
  end
end

If you want add new line or the separator, you can use the break_line or separator methods:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  toolbar do
    append :bold, break_line
    append separator, :italic
  end
end

block_toolbar(*items, should_group_when_full: true, &block) method

Define block toolbar items and their grouping behavior

API is identical to the toolbar method, but it's used for block toolbar items. The example below shows how to define block toolbar items:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  block_toolbar :paragraph, :heading, :blockQuote, :|, :bulletedList, :numberedList, :todoList
end

It is useful when you want to use Block Balloon Editor or Block Toolbar features.

balloon_toolbar(*items, should_group_when_full: true, &block) method

Define balloon toolbar items and their grouping behavior

API is identical to the toolbar method, but it's used for balloon toolbar items. The example below shows how to define balloon toolbar items:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  balloon_toolbar :bold, :italic, :underline, :link, :insertImage, :mediaEmbed, :insertTable, :blockQuote
end

It is useful when you want to use Balloon Editor or Balloon Toolbar features.

menubar(visible: true) method

Set the visibility and options for the editor menubar

Defines the visibility of the menubar. By default, it's set to true.

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  toolbar :undo, :redo, :|, :heading, :|, :bold, :italic, :underline, :|,
          :link, :insertImage, :ckbox, :mediaEmbed, :insertTable, :blockQuote, :|,
          :bulletedList, :numberedList, :todoList, :outdent, :indent
end

configure(name, value) method

Add custom configuration options to the editor instance

Allows 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 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.

For example, you can use it to configure font family dropdown to show only fonts available in specific elements:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  configure :fontFamily, {
    supportAllValues: true,
    options: [
      'default',
      'Arial, Helvetica, sans-serif',
      'Courier New, Courier, monospace',
      'Georgia, serif',
      'Lucida Sans Unicode, Lucida Grande, sans-serif',
      'Tahoma, Geneva, sans-serif',
      'Times New Roman, Times, serif',
      'Trebuchet MS, Helvetica, sans-serif',
      'Verdana, Geneva, sans-serif'
    ]
  }
end

plugin(name, premium:, import_name:) method

Register individual CKEditor plugins with optional premium flag

Defines 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.

The example below show how to import Bold plugin from the ckeditor5 npm package:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  plugin :Bold
end

In order to import a plugin from a custom ESM package, you can pass the import_name keyword argument:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  plugin :YourPlugin, import_name: 'your-package'
end

In order to import a plugin from a custom Window entry, you can pass the window_name keyword argument:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  plugin :YourPlugin, window_name: 'YourPlugin'
end

plugins(*names, **kwargs) method

Register multiple CKEditor plugins at once

Defines 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.


# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  plugins :Bold, :Italic, :Underline, :Link
end

Methods 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:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  plugins do
    remove :Heading
  end
end

inline_plugin(name, code) method

Define custom CKEditor plugins directly in the configuration

โš ๏ธ 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. The example below shows how to define a custom plugin that highlights the text:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  inline_plugin :MyCustomPlugin, <<~JS
    const { Plugin } = await import( 'ckeditor5' );

    return class extends Plugin {
      static get pluginName() {
        return 'MyCustomPlugin';
      }

      init() {
        const config = this.editor.config.get('myCustomPlugin') || {};

        // ... Your plugin code
      }
    }
  JS
end

To configure the custom plugin, use the configure method in your initializer. The example below shows how to configure the myCustomPlugin:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  configure :myCustomPlugin, {
    option1: 'value1',
    option2: 'value2'
  }
end

This approach is resistant to XSS attacks as it avoids inline JavaScript.

external_plugin(name, script:, import_as: nil, window_name: nil, stylesheets: []) method

Define external CKEditor plugins directly in the configuration

Defines 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.

The example below shows how to define an external plugin that highlights the text:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  external_plugin :MyExternalPlugin,
                  script: 'https://example.com/my-external-plugin.js'
end

In order to import a plugin from a custom ESM package, you can pass the import_as keyword argument:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  external_plugin :MyExternalPlugin,
                  script: 'https://example.com/my-external-plugin.js',
                  import_as: 'Plugin'
end

It's equivalent to the following JavaScript code:

import { Plugin } from 'my-external-plugin';

In order to import a plugin from a custom Window entry, you can pass the window_name keyword argument:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  external_plugin :MyExternalPlugin,
                  script: 'https://example.com/my-external-plugin.js',
                  window_name: 'MyExternalPlugin'
end

It's equivalent to the following JavaScript code:

const Plugin = window.MyExternalPlugin;

In order to import a plugin with stylesheets, you can pass the stylesheets keyword argument:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  external_plugin :MyExternalPlugin,
                  script: 'https://example.com/my-external-plugin.js',
                  stylesheets: ['https://example.com/my-external-plugin.css']
end

simple_upload_adapter(url) method

Configure server-side image upload endpoint

Defines 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:


# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  simple_upload_adapter
  # or: simple_upload_adapter '/uploads'
end

wproofreader(version: nil, cdn: nil, **config) method

Configure WProofreader plugin

Defines the WProofreader plugin to be included in the editor. The example below shows how to include the WProofreader plugin:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  wproofreader serviceId: 'your-service-ID',
               srcUrl: 'https://svc.webspellchecker.net/spellcheck31/wscbundle/wscbundle.js'
end

The 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.

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  wproofreader version: '2.0.0',
               cdn: 'https://cdn.jsdelivr.net/npm/@ckeditor/ckeditor5-wproofreader@2.0.0/dist',
               serviceId: 'your-service-ID',
               srcUrl: 'https://svc.webspellchecker.net/spellcheck31/wscbundle/wscbundle.js'
end

If 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:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  wproofreader serviceId: 'your-service-ID',
               srcUrl: 'https://svc.webspellchecker.net/spellcheck31/wscbundle/wscbundle.js',
               language: :en_US,
               localization: :pl
end

For more info about the WProofreader plugin, check the official documentation.

Controller / View helpers ๐Ÿ“ฆ

ckeditor5_element_ref(selector) method

Defines a reference to a CKEditor 5 element.

In 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.

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  configure :yourPlugin, {
      element: ckeditor5_element_ref("body")
  }
end

ckeditor5_preset(name = nil, &block) method

The `ckeditor5_preset` method allows you to define a custom preset in your application controller.

It may be useful when you want to define a preset based on the current user or request.

# app/controllers/application_controller.rb

class ApplicationController < ActionController::Base
  def show
    @preset = ckeditor5_preset do
      version '44.1.0'

      toolbar :sourceEditing, :|, :bold, :italic, :underline, :strikethrough,
              :subscript, :superscript, :removeFormat, :|, :bulletedList, :numberedList,
              :fontFamily, :fontSize, :|, :link, :anchor, :|,
              :fontColor, :fontBackgroundColor

      plugins :Essentials, :Paragraph, :Bold, :Italic, :Underline, :Strikethrough,
              :Subscript, :Superscript, :RemoveFormat, :List, :Link, :Font,
              :FontFamily, :FontSize, :FontColor, :FontBackgroundColor, :SourceEditing, :Essentials, :Paragraph
    end
  end
end

In order to use the preset in the view, you can pass it to the ckeditor5_assets helper method:

<!-- app/views/demos/index.html.erb -->

<% content_for :head do %>
  <%= ckeditor5_assets preset: @preset %>
<% end %>

<%= ckeditor5_editor %>

If 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):

# app/controllers/application_controller.rb

class ApplicationController < ActionController::Base
  def show
    @preset = ckeditor5_preset(:default).override do
      version '44.1.0'

      toolbar :sourceEditing, :|, :bold, :italic, :underline, :strikethrough,
              :subscript, :superscript, :removeFormat, :|, :bulletedList, :numberedList,
              :fontFamily, :fontSize, :|, :link, :anchor, :|,
              :fontColor, :fontBackgroundColor

      plugins :Essentials, :Paragraph, :Bold, :Italic, :Underline, :Strikethrough,
              :Subscript, :Superscript, :RemoveFormat, :List, :Link, :Font,
              :FontFamily, :FontSize, :FontColor, :FontBackgroundColor, :SourceEditing, :Essentials, :Paragraph
    end
  end
end

Including CKEditor 5 assets ๐Ÿ“ฆ

To 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.

Keep 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.

Format ๐Ÿ“

Using default preset

The example below users the default preset defined here.

<!-- app/views/demos/index.html.erb -->

<% content_for :head do %>
  <%= ckeditor5_assets %>
<% end %>

If you want to fetch some additional translations, you can extend your initializer with the following configuration:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... rest of the configuration

  translations :pl, :es
end

Custom preset

To 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:

<!-- app/views/demos/index.html.erb -->

<% content_for :head do %>
  <%= ckeditor5_assets preset: :custom %>
<% end %>

<%-# This editor will use `custom` preset defined in `ckeditor5_assets` above %>
<%= ckeditor5_editor %>

In order to define such preset, you can use the following configuration:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... rest of the configuration

  presets.define :custom do
    # ... your preset configuration

    translations :pl, :es
  end
end

โš ๏ธ 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.

<!-- app/views/demos/index.html.erb -->

<% content_for :head do %>
  <%= ckeditor5_assets preset: :custom %>
<% end %>

<%= ckeditor5_editor preset: :default %>

Inline preset definition

It'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:

<!-- app/views/demos/index.html.erb -->

<% content_for :head do %>
  <%= ckeditor5_assets version: '43.3.0', cdn: :jsdelivr, translations: [:pl], license_key: '<YOUR KEY> OR GPL' %>
<% end %>

Lazy loading ๐Ÿš€

Expand to show more information about lazy loading

All 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.

It 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.

ckeditor5_lazy_javascript_tags helper

This method is slow as content is being loaded on the fly on the client side. Use it only when necessary.

If 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.

This 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.

The example below shows how to include the CKEditor 5 assets lazily:

<!-- app/views/demos/index.html.erb -->

<% content_for :head do %>
  <%= ckeditor5_lazy_javascript_tags %>
<% end %>

<%= turbo_frame_tag 'editor' do %>
  <%= ckeditor5_editor %>
<% end %>

โš ๏ธ 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).

If 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:

<!-- app/views/demos/index.html.erb -->

<% content_for :head do %>
  <%= ckeditor5_assets preset: :custom, lazy: true %>
<% end %>

<!-- This time preset will be inherited but stylesheets and js files will be injected on the client side. -->
<%= ckeditor5_editor %>

GPL usage ๐Ÿ†“

If 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.

Example:

<!-- app/views/demos/index.html.erb -->

<% content_for :head do %>
  <%= ckeditor5_assets %>
<% end %>

In that scenario it's recommended to add gpl method to the initializer along with the version:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  gpl
  version '44.1.0'
end

In order to use unpkg CDN, you can extend your initializer with the following configuration:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... rest of the configuration

  cdn :unpkg
end

However, you can also specify the CDN directly in the view:

<!-- app/views/demos/index.html.erb -->

<% content_for :head do %>
  <%= ckeditor5_assets cdn: :unpkg %>
<% end %>

or using helper function:

<!-- app/views/demos/index.html.erb -->

<% content_for :head do %>
  <%= ckeditor5_jsdelivr_assets %>
<% end %>

Commercial usage ๐Ÿ’ฐ

If you want to use CKEditor 5 under a commercial license, you have to specify license key. It can be done in the initializer:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  license_key 'your-license-key'
end
<!-- app/views/demos/index.html.erb -->

<% content_for :head do %>
  <%= ckeditor5_assets %>
<% end %>

or directly in the view:

<!-- app/views/demos/index.html.erb -->

<% content_for :head do %>
  <%= ckeditor5_assets license_key: 'your-license-key' %>
<% end %>

In this scenario, the assets are included from the official CKEditor 5 CDN which is more reliable and provides better performance, especially for commercial usage.

Editor placement ๐Ÿ—๏ธ

The 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.

Setting Initial Content ๐Ÿ“

You 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.

The example below shows how to set the initial content of the editor using the initial_data and language keyword arguments:

<!-- app/views/demos/index.html.erb -->

<%= ckeditor5_editor initial_data: "<p>Initial content</p>" %>

The example below shows how to set the initial content of the editor using the ckeditor5_editor helper block.

<!-- app/views/demos/index.html.erb -->

<%= ckeditor5_editor do %>
  <p>Initial content</p>
<% end %>

Watchdog ๐Ÿ•

CKEditor 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.

If you want to disable the watchdog, you can pass the watchdog keyword argument with the value false:

<!-- app/views/demos/index.html.erb -->

<%= ckeditor5_editor watchdog: false %>

Classic editor ๐Ÿ“

The classic editor is the most common type of editor. It provides a toolbar with various formatting options like bold, italic, underline, and link.

It looks like this:

CKEditor 5 Classic Editor in Ruby on Rails application with Menubar

The example below shows how to include the classic editor in your view:

<!-- app/views/demos/index.html.erb -->

<% content_for :head do %>
  <%= ckeditor5_assets %>
<% end %>

<%= ckeditor5_editor style: 'width: 600px' %>

You 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.

While example above uses predefined :default preset, you can use your custom presets by passing the preset keyword argument:

<!-- app/views/demos/index.html.erb -->

<% content_for :head do %>
  <%= ckeditor5_assets %>
<% end %>

<%= ckeditor5_editor preset: :custom, style: 'width: 600px' %>

If your configuration is even more complex, you can pass the config and type arguments with the configuration hash:

<!-- app/views/demos/index.html.erb -->

<% content_for :head do %>
  <%= ckeditor5_assets %>
<% end %>

<%= ckeditor5_editor type: :classic, config: { plugins: [:Bold, :Italic], toolbar: [:Bold, :Italic] }, style: 'width: 600px' %>

If 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:

<!-- app/views/demos/index.html.erb -->

<% content_for :head do %>
  <!-- You can override default preset in assets helper too. -->
  <%= ckeditor5_assets translations: [:pl] %>
<% end %>

<%= ckeditor5_editor extra_config: { toolbar: [:Bold, :Italic] }, style: 'width: 600px' %>

It's possible to define the height of the editor by passing the editable_height keyword argument with the value in pixels:

<!-- app/views/demos/index.html.erb -->

<% content_for :head do %>
  <%= ckeditor5_assets %>
<% end %>

<%= ckeditor5_editor editable_height: 300 %>

Multiroot editor ๐ŸŒณ

The 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.

  • ckeditor5_editor: Defines the editor instance.
  • ckeditor5_editable: Defines the editable areas within the editor.
  • ckeditor5_toolbar: Defines the toolbar for the editor.

CKEditor 5 Multiroot Editor in Ruby on Rails application

If you want to use a multiroot editor, you can pass the type keyword argument with the value :multiroot:

<!-- app/views/demos/index.html.erb -->

<% content_for :head do %>
  <%= ckeditor5_assets %>
<% end %>

<%= ckeditor5_editor type: :multiroot, style: 'width: 600px' do %>
  <%= ckeditor5_toolbar %>
  <br>
  <%= ckeditor5_editable 'toolbar', style: 'border: 1px solid var(--ck-color-base-border);' do %>
    This is a toolbar editable
  <% end %>
  <br>
  <%= ckeditor5_editable 'content', style: 'border: 1px solid var(--ck-color-base-border)' %>
  <br>
<% end %>

Roots can be defined later to the editor by simply adding new elements rendered by ckeditor5_editable helper.

Inline editor ๐Ÿ“

Inline 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.

CKEditor 5 Inline Editor in Ruby on Rails application

If you want to use an inline editor, you can pass the type keyword argument with the value :inline:

<!-- app/views/demos/index.html.erb -->

<% content_for :head do %>
  <%= ckeditor5_assets %>
<% end %>

<%= ckeditor5_editor type: :inline, style: 'width: 600px' %>

Balloon editor ๐ŸŽˆ

Balloon 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.

CKEditor 5 Balloon Editor in Ruby on Rails application

If you want to use a balloon editor, you can pass the type keyword argument with the value :balloon:

<!-- app/views/demos/index.html.erb -->

<% content_for :head do %>
  <%= ckeditor5_assets %>
<% end %>

<%= ckeditor5_editor type: :balloon, style: 'width: 600px' %>

Decoupled editor ๐ŸŒ

Decoupled 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.

CKEditor 5 Decoupled Editor in Ruby on Rails application

If you want to use a decoupled editor, you can pass the type keyword argument with the value :decoupled:

<!-- app/views/demos/index.html.erb -->

<% content_for :head do %>
  <%= ckeditor5_assets %>
<% end %>

<%= ckeditor5_editor type: :decoupled, style: 'width: 600px' do %>
  <div class="menubar-container">
    <%= ckeditor5_menubar %>
  </div>

  <div class="toolbar-container">
    <%= ckeditor5_toolbar %>
  </div>

  <div class="editable-container">
    <%= ckeditor5_editable %>
  </div>
<% end %>

Using Context ๐Ÿ“ฆ

Context 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.

CKEditor 5 Context

Using Context in CKEditor 5 ๐Ÿ”„

Format of the ckeditor5_context helper:

<!-- app/views/demos/index.html.erb -->

<%= ckeditor5_context @context_preset do %>
  <%= ckeditor5_editor %>
  <%= ckeditor5_editor %>
<% end %>

The 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.

Example usage of ckeditor5_context helper ๐Ÿ“

In your view:

<!-- app/views/demos/index.html.erb -->

<% content_for :head do %>
  <%= ckeditor5_assets preset: :ultrabasic %>
<% end %>

<%= ckeditor5_context @context_preset do %>
  <%= ckeditor5_editor initial_data: 'Hello World' %>

  <br>

  <%= ckeditor5_editor initial_data: 'Hello World 2' %>
<% end %>

In your controller:

# app/controllers/demos_controller.rb

class DemosController < ApplicationController
  def index
    @context_preset = ckeditor5_context_preset do
      # Syntax is identical to the `toolbar` method of the preset configuration.
      toolbar :bold, :italic

      # It's possible to define plugins. Syntax is identical to the `plugins` method of the preset configuration.
      # Example:
      # plugin :Bold
      # inline_plugin :MyCustomPlugin, '...'
    end
  end
end

It's possible to omit the preset argument, in that case the empty preset will be used.

<!-- app/views/demos/index.html.erb -->

<%= ckeditor5_context do %>
  <%= ckeditor5_editor %>
  <%= ckeditor5_editor %>
<% end %>

See demo for more details.

How to access editor instance? ๐Ÿค”

You can access the editor instance using plain HTML and JavaScript, as CKEditor 5 is a web component with defined instance, instancePromise and editables properties.

For example:

<!-- app/views/demos/index.html.erb -->

<% content_for :head do %>
  <%= ckeditor5_assets %>
<% end %>

<%= ckeditor5_editor style: 'width: 600px', id: 'editor' %>

โš ๏ธ 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.

document.getElementById('editor').instance

๐Ÿ‘Œ Accessing the editor instance using instancePromise property. It's a promise that resolves to the editor instance when the editor is ready.

document.getElementById('editor').instancePromise.then(editor => {
  console.log(editor);
});

โœ… Accessing the editor through the runAfterEditorReady helper method. It's a safe way to access the editor instance when the editor is ready.

document.getElementById('editor').runAfterEditorReady(editor => {
  console.log(editor);
});

Common Tasks and Solutions ๐Ÿ’ก

This section covers frequent questions and scenarios when working with CKEditor 5 in Rails applications.

Setting Editor Language ๐ŸŒ

By 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.

Setting the language in the assets helper

Language specified here will be used for all editor instances on the page.

<!-- app/views/demos/index.html.erb -->

<% content_for :head do %>
  <%= ckeditor5_assets language: :pl %>
<% end %>

<%= ckeditor5_editor %>

Setting the language in the initializer

Language specified here will be used for all editor instances in your application.

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # Optional, it load multiple translation packs: translations :pl, :es
  language :pl
end

Setting the language on the editor level

Language 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.

<!-- app/views/demos/index.html.erb -->

<%= ckeditor5_editor language: :pl %>

Preloading multiple translation packs

You can preload multiple translation packs in the initializer using the translations method:

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  translations :pl, :es
end

Spell and Grammar Checking ๐Ÿ“

CKEditor 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.

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  wproofreader serviceId: 'your-service-ID',
               srcUrl: 'https://svc.webspellchecker.net/spellcheck31/wscbundle/wscbundle.js'
end

See wproofreader(version: nil, cdn: nil, **config) method for more information about the WProofreader plugin configuration.

See the official documentation for more information about the WProofreader plugin.

Integrating with Forms ๐Ÿ“‹

You 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:

Rails form builder integration

<!-- app/views/demos/index.html.erb -->

<%= form_for @post do |f| %>
  <%= f.label :content %>
  <%= f.ckeditor5 :content, required: true, style: 'width: 700px', initial_data: 'Hello World!' %>
<% end %>

Simple form integration

<!-- app/views/demos/index.html.erb -->

<%= simple_form_for :demo, url: '/demos', html: { novalidate: false } do |f| %>
  <div class="form-group">
    <%= f.input :content, as: :ckeditor5, initial_data: 'Hello, World 12!', input_html: { style: 'width: 600px' }, required: true %>
  </div>

  <div class="form-group mt-3">
    <%= f.button :submit, 'Save', class: 'btn btn-primary' %>
  </div>
<% end %>

Integration with Turbolinks ๐Ÿš€

If 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.

Your view should look like this:

<!-- app/views/demos/index.html.erb -->

<% content_for :head do %>
  <%= ckeditor5_lazy_javascript_tags %>
<% end %>

Your ajax partial should look like this:

<!-- app/views/demos/_form.html.erb -->

<!-- Presets and other configuration as usual -->
<%= ckeditor5_editor %>

This 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 section for more information and demos on how to use this method.

Custom Styling ๐ŸŽจ

You 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:

<!-- app/views/demos/index.html.erb -->

<%= ckeditor5_editor style: 'height: 400px; margin: 20px;', class: 'your_css_class', id: 'your_id' %>

Custom plugins ๐Ÿงฉ

You 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.

The example below shows how to define a custom plugin that allows toggling the highlight of the selected text:

CKEditor 5 Custom Highlight Plugin in Ruby on Rails application

# config/initializers/ckeditor5.rb

CKEditor5::Rails.configure do
  # ... other configuration

  # 1. You can also use "window_name" option to import plugin from window object:

  # plugin :MyPlugin, window_name: 'MyPlugin'

  # 2. Create JavaScript file in app/javascript/custom_plugins/highlight.js,
  #    add it to import map and then load it in initializer:

  # plugin :MyCustomPlugin, import_name: 'my-custom-plugin'

  # 3 Create JavaScript file in app/javascript/custom_plugins/highlight.js
  #   and then load it in initializer:

  # In Ruby initializer you can also load plugin code directly from file:
  inline_plugin :MyCustomPlugin, File.read(
    Rails.root.join('app/javascript/custom_plugins/highlight.js')
  )

  # 4. Or even define it inline:
  # inline_plugin :MyCustomPlugin,  <<~JS
  #    const { Plugin } = await import( 'ckeditor5' );
  #
  #    return class MyCustomPlugin extends Plugin {
  #      // ...
  #    }
  # JS

  # Add item to beginning of the toolbar.
  toolbar do
    prepend :highlight
  end
end
Example of Custom Highlight Plugin ๐ŸŽจ
// app/javascript/custom_plugins/highlight.js
import { Plugin, Command, ButtonView } from 'ckeditor5';

return class MyCustomPlugin extends Plugin {
  static get pluginName() {
    return 'MyCustomPlugin';
  }

  init() {
    const editor = this.editor;

    // Define schema for highlight attribute
    editor.model.schema.extend('$text', { allowAttributes: 'highlight' });

    // Define conversion between model and view
    editor.conversion.attributeToElement({
      model: 'highlight',
      view: {
        name: 'span',
        styles: {
          'background-color': 'yellow'
        }
      }
    });

    // Create command that handles highlighting logic
    // Command pattern is used to encapsulate all the logic related to executing an action
    const command = new HighlightCommand(editor);

    // Register command in editor
    editor.commands.add('highlight', command);

    // Add UI button
    editor.ui.componentFactory.add('highlight', locale => {
      const view = new ButtonView(locale);

      // Bind button state to command state using bind method
      // bind() allows to sync button state with command state automatically
      view.bind('isOn').to(command, 'value');

      view.set({
        label: 'Highlight',
        withText: true,
        tooltip: true
      });

      view.on('execute', () => {
        editor.execute('highlight');
        editor.editing.view.focus();
      });

      return view;
    });
  }
}

// Command class that handles the highlight feature
// isEnabled property determines if command can be executed
class HighlightCommand extends Command {
  execute() {
    const model = this.editor.model;
    const selection = model.document.selection;

    model.change(writer => {
      const ranges = model.schema.getValidRanges(selection.getRanges(), 'highlight');

      for (const range of ranges) {
        if (this.value) {
          writer.removeAttribute('highlight', range);
        } else {
          writer.setAttribute('highlight', true, range);
        }
      }
    });
  }

  refresh() {
    const model = this.editor.model;
    const selection = model.document.selection;
    const isAllowed = model.schema.checkAttributeInSelection(selection, 'highlight');

    // Set if command is enabled based on schema
    this.isEnabled = isAllowed;
    this.value = this.#isHighlightedNodeSelected();
  }

  // Check if the highlighted node is selected.
  #isHighlightedNodeSelected() {
    const { model } = this.editor
    const { schema } = model
    const selection = model.document.selection

    if (selection.isCollapsed) {
      return selection.hasAttribute('highlight')
    }

    return selection.getRanges().some(range =>
      Array
        .from(range.getItems())
        .some(item =>
          schema.checkAttribute(item, 'highlight') &&
          item.hasAttribute('highlight')
        )
    );
  }
}

Content Security Policy (CSP) ๐Ÿ›ก๏ธ

If 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:

# config/initializers/content_security_policy.rb

Rails.application.configure do
  config.content_security_policy do |policy|
    policy.default_src :self, :https
    policy.font_src :self, :https, :data
    policy.img_src :self, :https, :data
    policy.object_src :none
    policy.script_src "'strict-dynamic'"
    policy.style_src :self, :https
    policy.style_src_elem :self, :https, :unsafe_inline
    policy.style_src_attr :self, :https, :unsafe_inline
    policy.base_uri :self
  end

  config.content_security_policy_nonce_generator = ->(_request) { SecureRandom.base64(16) }
  config.content_security_policy_nonce_directives = %w[script-src style-src]
end

Events fired by the editor ๐Ÿ”Š

CKEditor 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.

editor-ready event

The event is fired when the initialization of the editor is completed. You can listen to it using the editor-ready event.

document.getElementById('editor').addEventListener('editor-ready', () => {
  console.log('Editor is ready');
});

editor-error event

The event is fired when the initialization of the editor fails. You can listen to it using the editor-error event.

document.getElementById('editor').addEventListener('editor-error', () => {
  console.log('Editor has an error');
});

editor-change event

The event is fired when the content of the editor changes. You can listen to it using the editor-change event.

document.getElementById('editor').addEventListener('editor-change', () => {
  console.log('Editor content has changed');
});

Inline event handling

You can also define event handlers directly in the view using the oneditorchange, oneditorerror, and oneditorready attributes.

<!-- app/views/demos/index.html.erb -->

<script type="text/javascript">
  function onEditorChange(event) {
    // event.detail.editor, event.detail.data
  }

  function onEditorError(event) {
    // event.detail.editor
  }

  function onEditorReady(event) {
    // event.detail.editor
  }
</script>

<%= ckeditor5_editor id: 'editor',
    oneditorchange: 'onEditorChange',
    oneditorerror: 'onEditorError',
    oneditorready: 'onEditorReady'
%>

Gem Development ๐Ÿ› 

If you want to contribute to the gem, you can clone the repository and run the following commands:

gem install bundler -v 2.5.22
bundle install
bundle exec guard -g rails

Running tests ๐Ÿงช

You can run the tests using the following command:

bundle exec rspec

If you want to watch the tests, you can use the following command:

bundle exec guard -g rspec

Trademarks ๐Ÿ“œ

CKEditorยฎ is a trademark of CKSource Holding sp. z o.o. All rights reserved. For more information about the license of CKEditorยฎ please visit CKEditor's licensing page.

This 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.

License ๐Ÿ“œ

This project is licensed under the terms of the GNU General Public License v2.0 or later. See the LICENSE file for details.

This project uses CKEditor 5 which is licensed under the terms of GNU General Public License Version 2 or later. For more information about CKEditor 5 licensing, please see their official documentation.