├── .changelog
└── .gitkeep
├── .circleci
└── config.yml
├── .editorconfig
├── .gitattributes
├── .github
└── PULL_REQUEST_TEMPLATE.md
├── .gitignore
├── .husky
└── pre-commit
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE.md
├── README.md
├── SECURITY.md
├── demos
├── cdn-multiroot-react
│ ├── App.tsx
│ ├── ContextMultiRootEditorDemo.tsx
│ ├── MultiRootEditorDemo.tsx
│ ├── MultiRootEditorRichDemo.tsx
│ ├── index.html
│ ├── main.tsx
│ └── useCKCdnMultiRootEditor.tsx
├── cdn-react
│ ├── App.tsx
│ ├── CKEditorCKBoxCloudDemo.tsx
│ ├── CKEditorCloudContextDemo.tsx
│ ├── CKEditorCloudDemo.tsx
│ ├── CKEditorCloudPluginsDemo.tsx
│ ├── getCKCdnClassicEditor.ts
│ ├── index.html
│ └── main.tsx
├── npm-multiroot-react
│ ├── App.tsx
│ ├── ContextMultiRootEditorDemo.tsx
│ ├── MultiRootEditor.tsx
│ ├── MultiRootEditorDemo.tsx
│ ├── MultiRootEditorRichDemo.tsx
│ ├── index.html
│ └── main.tsx
├── npm-react
│ ├── App.tsx
│ ├── ClassicEditor.tsx
│ ├── ContextDemo.tsx
│ ├── EditorDemo.tsx
│ ├── index.html
│ └── main.tsx
├── sample.jpg
└── tsconfig.json
├── eslint.config.js
├── index.html
├── package.json
├── pnpm-lock.yaml
├── pnpm-workspace.yaml
├── scripts
├── bump-year.js
├── ci
│ └── is-project-ready-to-release.js
├── postinstall.js
├── preparechangelog.js
├── preparepackages.js
├── publishpackages.js
└── utils
│ ├── constants.js
│ ├── getlistroptions.js
│ ├── parsearguments.js
│ └── preparepackagejson.js
├── src
├── ckeditor.tsx
├── cloud
│ ├── useCKEditorCloud.tsx
│ └── withCKEditorCloud.tsx
├── context
│ ├── ckeditorcontext.tsx
│ ├── setCKEditorReactContextMetadata.ts
│ └── useInitializedCKEditorsMap.ts
├── hooks
│ ├── useAsyncCallback.ts
│ ├── useAsyncValue.ts
│ ├── useInstantEditorEffect.ts
│ ├── useInstantEffect.ts
│ ├── useIsMountedRef.ts
│ ├── useIsUnmountedRef.ts
│ └── useRefSafeCallback.ts
├── index.ts
├── lifecycle
│ ├── LifeCycleEditorSemaphore.ts
│ ├── LifeCycleElementSemaphore.ts
│ └── useLifeCycleSemaphoreSyncRef.tsx
├── plugins
│ ├── ReactIntegrationUsageDataPlugin.ts
│ └── appendAllIntegrationPluginsToConfig.ts
├── useMultiRootEditor.tsx
└── utils
│ └── mergeRefs.ts
├── tests
├── _utils-tests
│ ├── context.test.tsx
│ └── editor.test.tsx
├── _utils
│ ├── classiceditor.js
│ ├── context.ts
│ ├── defer.js
│ ├── editor.ts
│ ├── expectToBeTruthy.ts
│ ├── multirooteditor.ts
│ ├── promisemanager.tsx
│ ├── timeout.js
│ └── turnOffErrors.ts
├── ckeditor.test.tsx
├── cloud
│ ├── useCKEditorCloud.test.tsx
│ └── withCKEditorCloud.test.tsx
├── context
│ ├── ckeditorcontext.test.tsx
│ └── useInitializedCKEditorsMap.test.tsx
├── hooks
│ ├── useAsyncCallback.test.tsx
│ ├── useAsyncValue.test.tsx
│ ├── useInstantEditorEffect.test.tsx
│ ├── useInstantEffect.test.tsx
│ ├── useIsMountedRef.test.tsx
│ ├── useIsUnmountedRef.test.tsx
│ └── useRefSafeCallback.test.tsx
├── index.test.tsx
├── integrations
│ ├── ckeditor-classiceditor.test.tsx
│ ├── ckeditor-editor-data.test.tsx
│ └── usemultirooteditor-multirooteditor.test.tsx
├── issues
│ ├── 349-destroy-context-and-editor.test.tsx
│ ├── 354-destroy-editor-inside-context.test.tsx
│ └── 39-frozen-browser.test.tsx
├── lifecycle
│ ├── LifeCycleElementSemaphore.test.tsx
│ └── useLifeCycleSemaphoreSyncRef.test.tsx
├── tsconfig.json
├── useMultiRootEditor.test.tsx
└── utils
│ └── mergeRefs.test.tsx
├── tsconfig.json
├── vite-env.d.ts
├── vite.config.ts
└── vitest-setup.ts
/.changelog/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ckeditor/ckeditor5-react/0537f2cfd3a854342a7ec5aa61cac4f1332472ea/.changelog/.gitkeep
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Configurations to normalize the IDE behavior.
2 | # http://editorconfig.org/
3 |
4 | root = true
5 |
6 | [*]
7 | indent_style = tab
8 | tab_width = 4
9 | charset = utf-8
10 | end_of_line = lf
11 | trim_trailing_whitespace = true
12 | insert_final_newline = true
13 |
14 | [package.json]
15 | indent_style = space
16 | tab_width = 2
17 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 |
3 | *.htaccess eol=lf
4 | *.cgi eol=lf
5 | *.sh eol=lf
6 |
7 | *.css text
8 | *.htm text
9 | *.html text
10 | *.js text
11 | *.json text
12 | *.php text
13 | *.txt text
14 | *.md text
15 |
16 | *.png -text
17 | *.gif -text
18 | *.jpg -text
19 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
13 |
14 | ### 🚀 Summary
15 |
16 | *A brief summary of what this PR changes.*
17 |
18 | ---
19 |
20 | ### 📌 Related issues
21 |
22 |
27 |
28 | * Closes #000
29 |
30 | ---
31 |
32 | ### 💡 Additional information
33 |
34 | *Optional: Notes on decisions, edge cases, or anything helpful for reviewers.*
35 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | coverage/
3 | dist/
4 | .idea
5 | .tmp
6 | /release/
7 | yarn.lock
8 |
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | # @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
2 | # For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
3 |
4 | pnpm lint-staged
5 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | Contributing
2 | ========================================
3 |
4 | See the [official contributors' guide to CKEditor 5](https://ckeditor.com/docs/ckeditor5/latest/framework/guides/contributing/contributing.html) to learn more about the general rules followed by the CKEditor 5 core team.
5 |
6 | See also the [Contributing](https://github.com/ckeditor/ckeditor5-react#contributing) section of this specific package to learn more about contributing to this package.
7 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | Software License Agreement
2 | ==========================
3 |
4 | **CKEditor 5 component for React** – https://github.com/ckeditor/ckeditor5-react
5 | Copyright (c) 2003-2025, [CKSource](http://cksource.com) Holding sp. z o.o. All rights reserved.
6 |
7 | Licensed under a dual-license model, this software is available under:
8 |
9 | * the [GNU General Public License Version 2 or later](http://www.gnu.org/licenses/gpl.html),
10 | * or commercial license terms from CKSource Holding sp. z o.o.
11 |
12 | For more information, see: [https://ckeditor.com/legal/ckeditor-licensing-options](https://ckeditor.com/legal/ckeditor-licensing-options).
13 |
14 | Sources of Intellectual Property Included in CKEditor
15 | -----------------------------------------------------
16 |
17 | Where not otherwise indicated, all CKEditor content is authored by CKSource engineers and consists of CKSource-owned intellectual property. In some specific instances, CKEditor will incorporate work done by developers outside of CKSource with their express permission.
18 |
19 | Trademarks
20 | ----------
21 |
22 | **CKEditor** is a trademark of [CKSource](http://cksource.com) Holding sp. z o.o. All other brand and product names are trademarks, registered trademarks or service marks of their respective holders.
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CKEditor 5 rich text editor component for React
2 |
3 | [](https://www.npmjs.com/package/@ckeditor/ckeditor5-react)
4 | [](https://app.circleci.com/pipelines/github/ckeditor/ckeditor5-react?branch=master)
5 | [](https://coveralls.io/github/ckeditor/ckeditor5-react?branch=master)
6 | 
7 |
8 | Official [CKEditor 5](https://ckeditor.com/ckeditor-5/) rich text editor component for React.
9 |
10 | ## [Developer Documentation](https://ckeditor.com/docs/ckeditor5/latest/builds/guides/integration/frameworks/react.html) 📖
11 |
12 | See the ["Rich text editor component for React"](https://ckeditor.com/docs/ckeditor5/latest/getting-started/installation/react/react.html) guide in the [CKEditor 5 documentation](https://ckeditor.com/docs/ckeditor5/latest) to learn more:
13 |
14 | * [Quick start](https://ckeditor.com/docs/ckeditor5/latest/getting-started/installation/react/react.html#quick-start)
15 | * [Using CKEditr 5 Builder](https://ckeditor.com/docs/ckeditor5/latest/getting-started/installation/react/react.html#using-ckeditor-5-builder)
16 | * [Installing from npm](https://ckeditor.com/docs/ckeditor5/latest/getting-started/installation/react/react.html#installing-from-npm)
17 | * [Component properties](https://ckeditor.com/docs/ckeditor5/latest/getting-started/installation/react/react.html#component-properties)
18 |
19 | ## Contributing
20 |
21 | > [!NOTE]
22 | > This project requires **pnpm v10** or higher. You can check your version with `pnpm --version` and update if needed with `npm install -g pnpm@latest`.
23 |
24 | After cloning this repository, install necessary dependencies:
25 |
26 | ```bash
27 | pnpm install
28 | ```
29 |
30 | ### Running the development server
31 |
32 | To manually test the editor integration with different versions of React, you can start the development server using one of the commands below:
33 |
34 | ```bash
35 | pnpm run dev:16 # Open the demo projects using React 16.
36 | pnpm run dev:18 # Open the demo projects using React 18.
37 | pnpm run dev:19 # Open the demo projects using React 19.
38 | ```
39 |
40 | ### Executing tests
41 |
42 | To test the editor integration against a set of automated tests, run the following command:
43 |
44 | ```bash
45 | pnpm run test
46 | ```
47 |
48 | If you want to run the tests in watch mode, use the following command:
49 |
50 | ```bash
51 | pnpm run test:watch
52 | ```
53 |
54 | ### Building the package
55 |
56 | To build the package that is ready to publish, use the following command:
57 |
58 | ```bash
59 | pnpm run build
60 | ```
61 |
62 | ## Releasing package
63 |
64 | CircleCI automates the release process and can release both channels: stable (`X.Y.Z`) and pre-releases (`X.Y.Z-alpha.X`, etc.).
65 |
66 | Before you start, you need to prepare the changelog entries.
67 |
68 | 1. Make sure the `#master` branch is up-to-date: `git fetch && git checkout master && git pull`.
69 | 1. Prepare a release branch: `git checkout -b release-[YYYYMMDD]` where `YYYYMMDD` is the current day.
70 | 1. Generate the changelog entries: `pnpm run release:prepare-changelog`.
71 | * You can specify the release date by passing the `--date` option, e.g., `--date=2025-06-11`.
72 | * By passing the `--dry-run` option, you can check what the script will do without actually modifying the files.
73 | * Read all the entries, correct poor wording and other issues, wrap code names in backticks to format them, etc.
74 | * Add the missing `the/a` articles, `()` to method names, "it's" -> "its", etc.
75 | * A newly introduced feature should have just one changelog entry – something like "The initial implementation of the FOO feature." with a description of what it does.
76 | 1. Commit all changes and prepare a new pull request targeting the `#master` branch.
77 | 1. Ping the `@ckeditor/ckeditor-5-platform` team to review the pull request and trigger the release process.
78 |
79 | ## License
80 |
81 | Licensed under a dual-license model, this software is available under:
82 |
83 | * the [GNU General Public License Version 2 or later](http://www.gnu.org/licenses/gpl.html),
84 | * or commercial license terms from CKSource Holding sp. z o.o.
85 |
86 | For more information, see: [https://ckeditor.com/legal/ckeditor-licensing-options](https://ckeditor.com/legal/ckeditor-licensing-options).
87 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Reporting security issues
2 |
3 | If you believe you have found a security issue in the CKEditor software, please contact us immediately.
4 |
5 | When reporting a suspected security problem, please bear this in mind:
6 |
7 | * Make sure to provide as many details as possible about the vulnerability.
8 | * Please do not disclose publicly any security issues until we fix them and publish security releases.
9 |
10 | Contact the security team at security@cksource.com. As soon as we receive the security report, we'll work promptly to confirm the issue and then to provide a security fix.
11 |
--------------------------------------------------------------------------------
/demos/cdn-multiroot-react/App.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
3 | * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4 | */
5 |
6 | import React, { StrictMode, useState } from 'react';
7 | import MultiRootEditorDemo from './MultiRootEditorDemo.js';
8 | import MultiRootEditorRichDemo from './MultiRootEditorRichDemo.js';
9 | import ContextMultiRootEditorDemo from './ContextMultiRootEditorDemo.js';
10 |
11 | type Demo = 'editor' | 'rich' | 'context';
12 |
13 | const multiRootEditorContent = {
14 | intro: '
This is an instance of the ' + 15 | 'multi-root editor build.
', 16 | content: 'It is the custom content
You can use this sample to validate whether your ' + 18 | 'custom build works fine.
' 19 | }; 20 | 21 | const rootsAttributes = { 22 | intro: { 23 | row: '1', 24 | order: 10 25 | }, 26 | content: { 27 | row: '1', 28 | order: 20 29 | }, 30 | outro: { 31 | row: '2', 32 | order: 10 33 | } 34 | }; 35 | 36 | export default function App(): JSX.Element { 37 | const [ demo, setDemo ] = useStateLorem ipsum dolor sit amet, consectetur adipiscing elit.
', 33 | content: 'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
' 34 | }, 35 | 36 | onReady: editor => { 37 | window.editor1 = editor; 38 | 39 | console.log( 'event: onChange', { editor } ); 40 | } 41 | } as MultiRootHookProps ); 42 | 43 | // Second editor initialization. 44 | const { 45 | editor: editor2, editableElements: editableElements2, toolbarElement: toolbarElement2 46 | } = useMultiRootEditor( { 47 | ...editorProps, 48 | data: { 49 | notes: 'Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
' 50 | }, 51 | 52 | onReady: editor => { 53 | window.editor2 = editor; 54 | 55 | console.log( 'event: onChange', { editor } ); 56 | } 57 | } as MultiRootHookProps ); 58 | 59 | // Function to simulate an error in the editor. 60 | // It is used for testing purposes to trigger the Watchdog to restart the editor. 61 | // Remove it in the actual integration. 62 | const simulateError = ( editor: any ) => { 63 | setTimeout( () => { 64 | const err: any = new Error( 'foo' ); 65 | 66 | err.context = editor; 67 | err.is = () => true; 68 | 69 | throw err; 70 | } ); 71 | }; 72 | 73 | return ( 74 | <> 75 |
77 | This sample demonstrates integration with CKEditorContext.
78 |
Component's events are logged to the console.
80 |
41 | This sample demonstrates the minimal React application that uses multi-root editor integration.
42 | You may use it as a starting point for your application.
43 |