Update to CKEditor 5 v29.x
When updating your CKEditor 5 installation, ensure 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.
Released on August 4, 2021.
For the entire list of changes introduced in version 29.1.0, see the release notes for CKEditor 5 v29.1.0.
Below are the most important changes that require your attention when upgrading to CKEditor 5 v29.1.0.
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 is also possible to match every possible value for these attributes by using the Boolean type with the true value. To avoid confusion about which pattern to use to match classes and styles, we decided to deprecate matching classes and styles using the 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
} );
Matcher pattern API change also improves how to define the link decorators (both manual decorator and automatic decorator). Similar to the Matcher feature API, you should define the style and class HTML attributes using the 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'
}
}
}
}
} )
Released on July 7, 2021.
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 release notes for CKEditor 5 v29.0.0.
To get to know the new editor UI for the image features, visit the image feature guide, especially:
Starting from v29.0.0, the existing Image plugin loads two independent plugins: ImageInline and ImageBlock.
- The
ImageInlineis a newly introduced plugin supporting the inline<img>tag nested in text (for example inside a paragraph). - The
ImageBlockmaintains the functionality of the previousImageplugin before v29.0.0. In the model, it uses theimageBlockelement (known asimagebefore v29.0.0).
Note: It is possible to load only one of these plugins, but only when building the editor from source.
An image caption is no longer automatically shown when selecting the image widget. You can now toggle its visibility with a ToggleImageCaptionCommand executed by the 'toggleImageCaption' toolbar button, both registered by the ImageCaption plugin.
To provide a valid data output, you can only add captions to block images. Adding a caption to an inline image will automatically convert it to a block image (which can be undone by the user).
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, we introduced the following changes:
-
A new set of buttons is available to manage the image type and appearance.
-
You can group the buttons provided by the
ImageStyleplugin into dropdowns.- A few default dropdowns are provided.
- In the editor configuration, you can declare a custom dropdown.
-
The name of the default block image style has changed from
fulltoblock(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 imageso 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.styleshas changed. You must wrap the list of the styles with theoptionsarray. Read more about theimage.stylesconfiguration.// 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' ] } } } );Copy code -
The format of the
imageStylehas 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' } ] } } } );Copy code -
Several changes have been also made to the
ImageStyleplugin API:- In the image style utilities module:
- The
defaultIconswere renamed toDEFAULT_ICONS. - The
defaultStyleswere renamed toDEFAULT_OPTIONS. - The
normalizeImageStyles()function was removed from the public API.
- The
- The
ImageStyleCommand#defaultStyleandImageStyleCommand#styleswere removed from the public API.
- In the image style utilities module:
Until v29.0.0, custom editor builds without ImageStyle and ImageToolbar plugins were possible. 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.
We recommend one of the following configurations as the minimum setup for the image toolbar:
-
For structured content editing:
Editor.create( document.querySelector( '#editor' ), { ... image: { toolbar: [ 'imageStyle:inline', 'imageStyle:block', 'imageStyle:side', '|', 'toggleImageCaption', 'imageTextAlternative' ] } } );Copy code -
For document-like editing:
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' ] } } );Copy code
See the image feature guide to learn more about the configuration of the image toolbar.
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, you can specify this in the ImageInsert plugin configuration.
-
The image utilities are now wrapped by the
ImageUtilsplugin.// 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 ) ) { // ... }Copy code -
The
insertImage()function:- No longer requires the
modelmodel instance to run. - Allows
ModelSelectableas a second argument (before onlyModelPositionwas accepted). - Supports the optional
imageTypeargument 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 );Copy code - No longer requires the
-
The
isImage()function recognizes both inline and block images (before only block images). -
There are two new helpers:
isBlockImageView()andisInlineImageView().
We removed the following helpers from the public API:
getSelectedImageWidget(),getViewImgFromWidget(),isImageAllowed(),isImageWidget(),toImageWidget()
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 using the CKEditor 5 Builder.
However, for integrations that build the editor from source, this means that 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.
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 using the CKEditor 5 Builder.
However, for integrations that build the editor from source, this means that to get CKFinder working properly, you must import the Image plugin (or either the ImageBlock or ImageInline plugin) 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.