How to upload different media types in ckEditor5 using custom upload Adaptor
Tags: ckeditor, nextjs, uploadadaptor
Published: 2024-01-18 22:30:39


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m5frn7shonqec5ujf0us.jpg)
hello my fellow developers 🙌

One of the main issues when dealing with **WYSIWYG** editors is uploading media (audio, video, image, etc.)
there are always limitations on how to upload certain media and of course developers have come up with professional solutions that might help you in managing your files (tools like [CKBox](https://ckeditor.com/ckbox/)), but what if you just want to use  your personal custom editor for a change?


## Step 1: Create a Nextjs project

to begin, open the terminal and run the following command:
`npx create-next-app`

you can also activate Typescript, ESlint and other options if you intend to use them in your project.


## Step 2: Create a custom build

you can choose your own ckeditor5 toolbar and plugins by going to [CKEditor Online Builder](https://ckeditor.com/ckeditor-5/online-builder/) and download the package.
unzip it and then copy the folder into your project's _src_ folder and change these lines in `ckeditor5/build/ckeditor.js`

```
acceptedType:r.map((t=>`image/${t}`)).join(","))
```
to:

```
acceptedType:'*'
```
----------------------

```
i=Array.from(n).filter((t=>s.test(t.type)))
```
to

```
i=Array.from(n)
```

and finally run `npm install file:src/ckeditor5`

you should now see `ckeditor5-custom-build` in your `package.json`

you should also install ckeditor package for react
`npm install @ckeditor/ckeditor5-react"`

## step 3: Add editor to page

make a new folder inside _app_ directory and rename it to blog.
then create a `page.tsx` and `CustomEditor` component:

``` javascript
// CustomEditor.js
import { CKEditor } from '@ckeditor/ckeditor5-react'
import Editor from 'ckeditor5-custom-build'
import axios from 'axios'

// upload Adaptor
function uploadAdapter(loader) {
  return {
    upload: () => {
      return new Promise((resolve, reject) => {
        const fd = new FormData()
        loader.file.then((file) => {
          // here check the mimetype and send request
          // to relevant backend api endpoint
          axios
            .post(`https://sample.com/files/${endPoint}`, fd)
            .then((res) => {
              resolve({
                default: res.data[0].fileAddress
              })
            })
            .catch((err) => {
              reject(err)
            })
        })
      })
    },
  }
}

function uploadPlugin(editor) {
  editor.plugins.get('FileRepository').createUploadAdapter = (loader) => {
    return uploadAdapter(loader)
  }

  // when upload completes, replace tag
  const imageUploadEditing = editor.plugins.get('ImageUploadEditing')
  imageUploadEditing.on('uploadComplete', (evt, { data, imageElement }) => {
    editor.model.change((writer) => {
      const view = editor.data.processor.toView(
        data.mediaType === 'video'
          ? `<video src='${data.default}' controls="controls"></video>`
          : data.mediaType === 'audio'
          ? `<audio src='${data.default}' controls="controls"></audio>`
          : `<img src='${data.default}' />`
      )
      const model = editor.data.toModel(view)
      editor.model.insertContent(model, editor.model.document.selection)
    })

    evt.stop()
    editor.editing.view.focus()
  })
}

const editorConfiguration = {
  placeholder: 'write your content...',
  extraPlugins: [uploadPlugin],
  toolbar: {
    items: [
      'heading',
      '|',
      'uploadImage',
      '|',
      'code',
      'codeBlock',
      'showBlocks',
      'sourceEditing',
      '|',
      'undo',
      'redo',
    ],
    shouldNotGroupWhenFull: true,
  },
  simpleUpload: {
    uploadUrl: `https://sample.com/files/editor`,
    fileTypes: ['.pdf', '.doc', '.docx', '.xls', '.xlsx'],
  },
  image: {
    upload: { types: ['mp4', 'pdf', 'mpeg', 'jpg', 'png'] },
  },

  htmlSupport: {
    allow: [
      {
        name: /.*/,
        attributes: true,
        classes: true,
        styles: true,
      },
    ],
  },
}

function CustomEditor(props) {
  return (
    <CKEditor
      editor={Editor}
      rows={7}
      data={props?.content}
      config={editorConfiguration}
      onChange={(event, editor) => {
        const newData = editor.getData()
        props.handleContent(newData)
      }}
    />
  )
}

export default CustomEditor
```

``` javascript
// blog/page.tsx

'use client';

import dynamic from 'next/dynamic.js';
import { useState } from 'react';

const CustomEditor = dynamic(
  () => {
    return import('./CustomEditor.jsx');
  },
  {ssr: false}
);

const Blog = () => {
  
  const [content, setContent] = useState("");
  
  return (
    <div>
      <CustomEditor id="content" content={content} handleContent={(newContent: any) => setContent(newContent)} />
    </div>
  );
};

export default Blog;

```

you can use your custom endpoints to send data to your backend and receive the file address. basically the code tries to replace the tag in the editor using [conversion](https://ckeditor.com/docs/ckeditor5/latest/api/module_engine_conversion_conversion-Conversion.html)

also don't forget you need to add your backend uploader for this code to work (I'm using multer and express in my own project).

Here's the result: 

![Uploaded Audio & Video](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p1xqi6zob2ar4jga1rf6.jpg)