Migration to CKEditor 5 v29.x
When updating your CKEditor 5 installation, make sure all the packages are the same version to avoid errors.
For custom builds, you may try removing the package-lock.json
or yarn.lock
files (if applicable) and reinstalling all packages before rebuilding the editor. For best results, make sure you use the most recent package versions.
# Migration to CKEditor 5 v29.1.0
For the entire list of changes introduced in version 29.1.0, see the changelog for CKEditor 5 v29.1.0.
Listed below are the most important changes that require your attention when upgrading to CKEditor 5 v29.1.0.
# Matcher pattern API change
Starting from v29.1.0, the Matcher
feature deprecated matching style
and class
HTML attributes using attributes
key-value pairs pattern.
The Matcher
feature allows to match styles and classes by using dedicated styles
and classes
patterns. Since v29.0.0 it’s also possible to match every possible value for these attributes by using Boolean type with true
value. Therefore, to avoid confusion which pattern should be used to match classes and styles, we decided to deprecate matching classes and styles using attributes
pattern.
Here is an example of changes you may need for proper integration with the Matcher
feature new API:
// Old code.
new Matcher( {
name: 'a',
attributes: {
'data-custom-attribute-1': /.*/,
'data-custom-attribute-2': /.*/,
style: true,
class: true
}
} );
// New code.
new Matcher( {
name: 'a',
attributes: {
'data-custom-attribute-1': /.*/,
'data-custom-attribute-2': /.*/
},
styles: true,
classes: true
} );
# Link decorators API change
Matcher pattern API change also improves how the link decorators should be defined (both manual decorator and automatic decorator). Similary to the Matcher
feature API, style
and class
HTML attributes should be defined using respectively classes
and styles
properties.
Here is an example of changes you may need for proper integration with the link decorators API change:
// Old code.
ClassicEditor
.create( ..., {
// ...
link: {
decorators: {
addGreenLink: {
mode: 'automatic',
attributes: {
class: 'my-green-link',
style: 'color:green;'
}
}
}
}
} )
// New code.
ClassicEditor
.create( ..., {
// ...
link: {
decorators: {
addGreenLink: {
mode: 'automatic',
classes: 'my-green-link',
styles: {
color: 'green'
}
}
}
}
} )
# Migration to CKEditor 5 v29.0.0
This migration guide enumerates the most important changes that require your attention when upgrading to CKEditor 5 v29.0.0 due to changes introduced in the Image
plugin and some other image-related features.
For the entire list of changes introduced in version 29.0.0, see the changelog for CKEditor 5 v29.0.0.
To get to know the new editor UI for the image features, visit the image feature guide, especially:
# Inline images
Starting from v29.0.0, the existing Image
plugin loads two independent plugins: ImageInline
and ImageBlock
, therefore both of them are included in all of the predefined editor builds by default.
- The
ImageInline
is a newly introduced plugin supporting the inline<img>
tag nested in text (e.g. inside a paragraph). - The
ImageBlock
maintains the functionality of the previousImage
plugin before v29.0.0. In the model, it uses theimageBlock
element (known asimage
before v29.0.0).
Note: It is possible to load only one of these plugins, but only when building the editor from source.
# Image caption
An image caption is no longer automatically shown when selecting the image widget. Its visibility can now be toggled with a ToggleImageCaptionCommand
executed by the 'toggleImageCaption'
toolbar button, both registered by the ImageCaption
plugin. The button is added to the default image toolbar in all of the predefined editor builds.
To provide a valid data output, captions can be added to block images only. Adding a caption to an inline image will automatically convert it to a block image (which can be undone by the user).
# Image styles
Since the appearance of the image in the document depends on the image type (block/inline), the ImageStyle
plugin is now in charge of switching between these types. Thus, the following changes have been introduced:
-
A new set of buttons is available to manage the image type and appearance.
-
There is a possibility to group the buttons provided by the
ImageStyle
plugin into dropdowns.- A few default dropdowns are provided.
- In the editor configuration, a custom dropdown can be declared.
-
The name of the default block image style has changed from
full
toblock
(as the default style for the inline images is calledinline
), the default content styles for these images remain the same. The button label has also changed and now readsCentered image
so that it reflects the actual appearance of the image. If you customized the default appearance of the block images, you can change the button label by modifying the existing image style. -
The format of the
config.image.styles
has changed. The list of the styles must be wrapped with theoptions
array. Read more about theimage.styles
configuration.// Before v29.0.0 Editor.create( document.querySelector( '#editor' ), { ... image: { styles: [ 'inline', 'full', 'side' ] } } ); // Since v29.0.0 Editor.create( document.querySelector( '#editor' ), { ... image: { styles: { options: [ 'inline', 'block', 'side' ] } } } );
-
The format of the
imageStyle
has changed. It must now provide information about the image types supporting a particular style. Read more about theImageStyleOptionDefinition
.// Before v29.0.0 Editor.create( document.querySelector( '#editor' ), { ... image: { styles: [ { name: 'alignLeft', title: 'Left aligned image', icon: objectLeft, className: 'image-style-align-left' } ] } } ); // Since v29.0.0 Editor.create( document.querySelector( '#editor' ), { ... image: { styles: { options: [ { name: 'alignLeft', title: 'Left aligned image', icon: objectLeft, // Image types (names of the model elements) supporting this style. modelElements: [ 'imageBlock', 'imageInline' ], className: 'image-style-align-left' } ] } } } );
-
Several changes have been also made to the
ImageStyle
plugin API:- In the image style utilities module:
- The
defaultIcons
were renamed toDEFAULT_ICONS
. - The
defaultStyles
were renamed toDEFAULT_OPTIONS
. - The
normalizeImageStyles()
function was removed from the public API.
- The
- The
ImageStyleCommand#defaultStyle
andImageStyleCommand#styles
were removed from the public API.
- In the image style utilities module:
# Image toolbar
Until v29.0.0, custom editor builds without ImageStyle
and ImageToolbar
plugins were possible because only block images were supported and captions were added by the user upon selecting the image.
Since v29.0.0, image styles and toolbar allow users to choose the type of image (inline or block) and give them a way to add or remove captions from block images via configurable buttons.
The user experience will degrade if either of these features is missing and this makes the image toolbar configuration essential.
Pre-configured editor builds come with ImageStyle
and ImageToolbar
plugins (and configuration) out-of-the-box. This information is mainly for developers who use custom editor builds in their integrations.
We recommended one of the following configurations as the minimum set-up for the image toolbar:
-
For the purposes of the structured content editing (implemented by default in the classic, balloon, balloon-block, and inline editor builds):
Editor.create( document.querySelector( '#editor' ), { ... image: { toolbar: [ 'imageStyle:inline', 'imageStyle:block', 'imageStyle:side', '|', 'toggleImageCaption', 'imageTextAlternative' ] } } );
-
For the purposes of the document-like editing (implemented by default in the decoupled document build).
Editor.create( document.querySelector( '#editor' ), { ... image: { toolbar: [ 'toggleImageCaption', 'imageStyle:inline', // A dropdown containing `alignLeft` and `alignRight` options. 'imageStyle:wrapText', // A dropdown containing `alignBlockLeft`, `block` (default) and `alignBlockRight` options. 'imageStyle:breakText' ] } } );
See the image feature guide to learn more about the configuration of the image toolbar.
# Inserting images
Since v29.0.0 inserting (also: pasting, dropping) an image in the middle of text will no longer split it if the ImageInline
plugin is loaded (default). If you prefer the old behavior in your integration, this can be specified in the ImageInsert
plugin configuration.
# Image utilities
-
The image utilities are now wrapped by the
ImageUtils
plugin.// Before v29.0.0 import { isImage } from './utils'; const selectedElement = editor.model.document.selection.getSelectedElement(); if ( isImage( selectedElement ) ) { // ... } // Since v29.0.0 // ... const imageUtils = this.editor.plugins.get( 'ImageUtils' ); const selectedElement = editor.model.document.selection.getSelectedElement(); if ( imageUtils.isImage( selectedElement ) ) { // ... }
-
The
insertImage()
function:- No longer requires the
model
model instance to run. - Allows
Selectable
as a second argument (previously onlyPosition
was accepted). - Supports the optional
imageType
argument to force the type of the image to be inserted.
// Before v29.0.0 import { insertImage } from './utils'; const src = 'path/to/image.jpg'; const model = ths.editor.model; const selection = model.document.selection; const position = model.createPositionAt( selection.getSelectedElement() ); insertImage( model, { src }, position ); // Since v29.0.0 const src = 'path/to/image.jpg'; const selection = this.editor.model.document.selection; const imageUtils = this.editor.plugins.get( 'ImageUtils' ); const imageType = 'imageBlock'; imageUtils.insertImage( { src }, selection, imageType );
- No longer requires the
-
The
isImage()
function recognizes both inline and block images (previously only block images). -
There are two new helpers:
isBlockImageView()
andisInlineImageView()
.
The following helpers were removed from the public API:
getSelectedImageWidget()
,getViewImgFromWidget()
,isImageAllowed()
,isImageWidget()
,toImageWidget()
# EasyImage
plugin
Please note that the EasyImage
plugin is no longer automatically importing the Image
plugin as a dependency. This allows using it alone with either ImageBlock
or ImageInline
without loading the other one.
This decoupling does not have an impact on integrations based on official editor builds or using the CKEditor 5 online builder.
However, for integrations that build the editor from source, this means that in order to get Easy Image working properly, the Image
plugin (or either the ImageBlock
or ImageInline
plugin) must be imported separately:
import EasyImage from '@ckeditor/ckeditor5-easy-image/src/easyimage';
import Image from '@ckeditor/ckeditor5-image/src/image';
ClassicEditor
.create( document.querySelector( '#editor' ), {
plugins: [ EasyImage, Image, ... ],
toolbar: [ 'uploadImage', ... ],
// ...
} )
.then( ... )
.catch( ... );
Check out the comprehensive installation guide to images in CKEditor 5 to learn more.
# CKFinder
plugin
Please note that the CKFinder
plugin is no longer automatically importing the Image
plugin as a dependency. This allows using it alone with either ImageBlock
or ImageInline
without loading the other one.
This decoupling does not have an impact on integrations based on official editor builds or using the CKEditor 5 online builder.
However, for integrations that build the editor from source, this means that in order to get CKFinder working properly, the Image
plugin (or either the ImageBlock
or ImageInline
plugin) must be imported separately:
import CKFinder from '@ckeditor/ckeditor5-ckfinder/src/ckfider';
import Image from '@ckeditor/ckeditor5-image/src/image';
ClassicEditor
.create( document.querySelector( '#editor' ), {
plugins: [ CKFinder, Image, ... ],
toolbar: [ 'uploadImage', ... ],
ckfinder: {
// Feature configuration.
}
} )
.then( ... )
.catch( ... );
Check out the comprehensive installation guide to images in CKEditor 5 to learn more.
Every day, we work hard to keep our documentation complete. Have you spotted an outdated information? Is something missing? Please report it via our issue tracker.