In this blog, we will learn to build a custom image upload plugin to upload images to CKEditor5 (Classic Editor) using SharePoint Framework (SPFx).

What is Classic Editor in CKEditor5?
Classic editor is what most users traditionally associate with a rich text editor — a toolbar with an editing area placed in a specific position on the page, usually as a part of a form that you use to submit some content to the server.
Note: Ckeditor5 Classic Editor is not yet supported in IE11 browser check here.
Below code tested in Chrome, Mozilla and Edge.
Code Usage:
Install "ckeditor5-classic" from your node package manager console as shown below.
  1. PS C:\XXXX\SPFxSolutions\SpFxRichTextEditor>npm install --save ckeditor5-classic
Import "Classic Editor" to your tsx file.
  1. import ClassicEditor from 'ckeditor5-classic';
Create "MyUploadAdapter.ts" file as shown below.
  1. /* this is my custom Image file adapter */
  2. export default class MyUploadAdapter {
  3. loader:any;
  4. reader:any;
  5. constructor(loader) {
  6. // The file loader instance to use during the upload.
  7. this.loader = loader;
  8. }
  9. //Starts the upload process.
  10. upload() {
  11. return this.loader.file
  12. .then(file => new Promise((resolve, reject) => {
  13. this._initListeners(resolve, reject, file);
  14. }));
  15. }
  16. _initListeners(resolve, reject, file) {
  17. console.log(file.name);
  18. const reader = this.reader = new FileReader();
  19. reader.addEventListener('load', () => {
  20. resolve({ default: reader.result });
  21. });
  22. reader.addEventListener('error', err => {
  23. reject(err);
  24. });
  25. reader.addEventListener('abort', () => {
  26. reject();
  27. });
  28. this.loader.file.then(file => {
  29. reader.readAsDataURL(file);
  30. reader.result
  31. });
  32. }
  33. abort() {
  34. this.reader.abort();
  35. }
  36. }
Import "MyUploadAdapter" to your tsx file.
  1. import MyUploadAdapter from './MyUploadAdapter';
Import "Jquery" plugin to your tsx file.
  1. import * as $ from 'jquery';
Initiate default toolbar configuration settings for Classic Editor.
  1. ClassicEditor.defaultConfig = {
  2. toolbar: {
  3. items: [
  4. 'heading',
  5. '|',
  6. 'bold',
  7. 'italic',
  8. 'fontSize',
  9. 'fontFamily',
  10. 'fontColor',
  11. 'fontBackgroundColor',
  12. 'link',
  13. 'bulletedList',
  14. 'numberedList',
  15. 'imageUpload',
  16. 'insertTable',
  17. 'blockQuote',
  18. 'undo',
  19. 'redo'
  20. ]
  21. },
  22. image: {
  23. toolbar: [
  24. 'imageStyle:full',
  25. 'imageStyle:side',
  26. '|',
  27. 'imageTextAlternative'
  28. ]
  29. },
  30. fontFamily: {
  31. options: [
  32. 'Arial',
  33. 'Helvetica, sans-serif',
  34. 'Courier New, Courier, monospace',
  35. 'Georgia, serif',
  36. 'Lucida Sans Unicode, Lucida Grande, sans-serif',
  37. 'Tahoma, Geneva, sans-serif',
  38. 'Times New Roman, Times, serif',
  39. 'Trebuchet MS, Helvetica, sans-serif',
  40. 'Verdana, Geneva, sans-serif'
  41. ]
  42. },
  43. language: 'en'
  44. };
Declare the state variable to store ckeditor event
  1. export interface ICKeditorState {
  2. CKEditorEvent:any;
  3. }
Initiatlize the state variable in your constructor
  1. constructor(props: ISpFxRichTextEditorProps) {
  2. super(props);
  3. this.state = {
  4. CKEditorEvent:''
  5. };
  6. }
  7. }
Insert text area to render the CKeditor5 on load.
  1. public render(){
  2. return (
  3. <div>
  4. <textarea id="editor1"></textarea>
  5. </div>
  6. );
  7. }
Replace text area with CKEditor5 on componentDidMount.
  1. componentDidMount(){
  2. this.InitializeCKeditor();
  3. }
  1. /* Load CKeditor RTE*/
  2. public InitializeCKeditor(): void {
  3. try {
  4. /*Replace textarea with classic editor*/
  5. ClassicEditor
  6. .create(document.querySelector("#editor1"), {
  7. extraPlugins: [this.MyUploadAdapterPlugin]
  8. }).then(editor => {
  9. console.log("CKEditor5 initiated");
  10. /*store the ckeditor event in state variable */
  11. this.setState({CKEditorEvent:editor});
  12. }).catch(error => {
  13. console.log("Error in Classic Editor Create " + error);
  14. });
  15. } catch (error) {
  16. console.log("Error in InitializeCKeditor " + error);
  17. }
  18. }
Define Custom image upload adapter plugin
  1. public MyUploadAdapterPlugin(editor) {
  2. editor.plugins.get('FileRepository').createUploadAdapter = function (loader) {
  3. /* Initialize MyUploadAdapter class to initiate custom upload adapter */
  4. return new MyUploadAdapter(loader);
  5. };
  6. }
Please feel free to share your comments.
Hope this helps !!!!!