CKEditor 5 was introduced in Drupal 9.3 and is now the default WYSIWYG editor in Drupal 10. It’s a complete overhaul of its predecessor — every single aspect was redesigned for a vastly improved content editing experience. But the power and flexibility of the editor’s new framework comes with a cost: a sharp learning curve for plugin developers.

Luckily, the ever-resourceful Drupal community has come to the rescue with various contrib modules to enhance CKEditor 5 in Drupal 10. In this article, we’ll be diving into one of my favourites for lessening the learning curve: the CKEditor5 Embedded Content module.

Let’s take a closer look at:

Why Use the Module?

As a developer, you’ll recognize the challenge of giving content editors the right level of creative freedom. They need enough flexibility to build engaging content, but not so much that they can create serious issues.

But what if content editors could insert themed content without needing HTML editing permissions? The CKEditor5 Embedded Content Module makes it possible.

Using this module, you can enable content editors to embed things like buttons, styling options, social media code and highlighted sections. They’ll even see the rendered results directly in the editor. 

How Does it Work?

The CKEditor5 Embedded Content module provides a new Drupal plugin called EmbeddedContent. This acts like a middleware layer between the CKEditor 5 API and Drupal. A typical instance of the EmbeddedContent plugin includes the default configuration, the configuration form, and the build() method returning the render array. Using render arrays means you can harness all the power of Twig for the CKEditor 5 plugin (e.g. rendering the UI Patterns or single directory components.)

What Does it Look Like?

The module comes with the ckeditor5_embedded_content_examples submodule, which contains some simple but handy examples.

Clicking on the toolbar button brings up a modal form. The first element is a dropdown where you can select any of the EmbeddedContent plugins implemented on the website. The rest of the form changes dynamically depending on which EmbeddedContent plugin you select.

 

The dropdown menu for embedded content

 

What’s Happening Under the Hood?

Let’s get a little more technical, shall we? We’re going to explore the underlying workings of CKEditor5 Embedded Content using the ckeditor5_embedded_content_examples submodule

Folder Structure

As you can see below, the example has three EmbeddedContent plugins, three templates (one for each plugin), and the hook_theme() in the .module file defining those templates.

 

the three possible templates, CallToAction, StyledList and Tweet

 

EmbeddedContent Plugin Structure 

Let’s look at the CallToAction plugin shipped with ckeditor5_embedded_content_examples.

First, we define the default plugin configuration (in other words, the variables that we will pass to the twig template.)

public function defaultConfiguration() {
   return [
     'url' => NULL,
     'text' => NULL,
   ];
 }

Next, we define the render array. Effectively, it contains the same variables plus the theme defined in the hook_theme().

public function build(): array {
   return [
     '#theme' => 'ckeditor5_embedded_content_call_to_action',
     '#url' => $this->configuration['url'],
     '#text' => $this->configuration['text'],
   ];
 }

And finally, we have the plugin configuration form: a simple Drupal Form API form.

public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
   $form['url'] = [
     '#type' => 'url',
     '#title' => $this->t('Url'),
     '#default_value' => $this->configuration['url'],
     '#required' => TRUE,
   ];
   $form['text'] = [
     '#type' => 'textfield',
     '#title' => $this->t('text'),
     '#default_value' => $this->configuration['text'],
     '#required' => TRUE,
   ];
   return $form;
 }

Theming 

As you can see below, the theme and the template are pretty standard.

function ckeditor5_embedded_content_examples_theme($existing, $type, $theme, $path) {
 return [
   'ckeditor5_embedded_content_call_to_action' => [
     'variables' => [
       'text' => NULL,
       'url' => NULL,
     ],
     'template' => 'embedded-content/call-to-action',
   ],
 ];
}
<p>
 <a href="{{ url }}" style="background:blue;color:white;border-radius: 1rem;font-size: 2rem;padding:1rem">
   {{ text }}
 </a>
</p>

Plugin’s Output

More interesting is how the plugin’s output looks in CKEditor. The widget takes up its entire width. 

 

The plugin widget

 

<embedded-content data-plugin-id="call_to_action" data-plugin-config="{&quot;url&quot;:&quot;https:\/\/evolvingweb.com\/&quot;,&quot;text&quot;:&quot;Click me!&quot;}">&nbsp;</embedded-content>

The actual output generated is the specific embedded-content tag, which has 2 data attributes:

  • data-plugin-id with the plugin name
  • data-plugin-config containing the string with the variables coming from the configuration form

Are There Any Limitations?

The CKEditor5 Embedded Content module has a few limitations to be aware of. Firstly, the CKEditor 5 plugin implements the block widget that takes the whole width of the editor — so the module may not be suitable if you need to implement an inline element.

Another consideration is that the plugin UI is limited to a Drupal Form API form in a modal window. This means it doesn’t offer the same level of flexibility as the table plugin for example. 

What’s Happening with Version 2?

Version 2.x of the CKEditor 5 Embedded Content module is under active development and will facilitate:

Version 2 is still in the alpha version. You can download the module and explore it yourself, but keep in mind that it is still under active development at the moment. 

So there you have it! The CKEditor 5 Embedded Content module is a great tool for enabling content editors to leverage your website’s theme and the full power of CKEditor 5. Stay tuned for upcoming articles exploring more use cases!

And remember we’re always on hand to support your organization with web development, maintenance, and other digital services