You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

594 lines
18 KiB

:packageName: tinymce-react
ifeval::["{productUse}" == "bundle"]
IMPORTANT: {companyname} does not recommend bundling the `tinymce` package. Bundling {productname} can be complex and error prone.
endif::[]
The https://github.com/tinymce/tinymce-react[Official {productname} React component] integrates {productname} into React projects. This procedure creates a https://github.com/vitejs/vite-plugin-react-swc[basic React application] containing a {productname} editor.
For examples of the {productname} integration, visit https://tinymce.github.io/tinymce-react/[the tinymce-react storybook].
== Prerequisites
This procedure requires https://nodejs.org/[Node.js (and npm)].
== Procedure
. Use the https://github.com/vitejs/vite[Vite] package and the https://github.com/vitejs/vite-plugin-react-swc[React SWC plugin] to create a new React project named `+tinymce-react-demo+`.
+
[source,sh]
----
# npm 7+, extra double-dash is needed
npm create vite@5 tinymce-react-demo -- --template react-swc
----
. Change to the newly created directory.
+
[source,sh]
----
cd tinymce-react-demo
----
ifeval::["{productSource}" == "cloud"]
. Install the `+@tinymce/tinymce-react+` package.
+
[source,sh]
----
npm install @tinymce/tinymce-react
----
. Using a text editor, open `+./src/App.jsx+` and replace the contents with:
+
[source,jsx]
----
import { useRef } from 'react';
import { Editor } from '@tinymce/tinymce-react';
import './App.css';
export default function App() {
const editorRef = useRef(null);
const log = () => {
if (editorRef.current) {
console.log(editorRef.current.getContent());
}
};
return (
<>
<Editor
apiKey='no-api-key'
onInit={ (_evt, editor) => editorRef.current = editor }
initialValue="<p>This is the initial content of the editor.</p>"
init={{
height: 500,
menubar: false,
plugins: [
'advlist', 'autolink', 'lists', 'link', 'image', 'charmap', 'preview',
'anchor', 'searchreplace', 'visualblocks', 'code', 'fullscreen',
'insertdatetime', 'media', 'table', 'code', 'help', 'wordcount'
],
toolbar: 'undo redo | blocks | ' +
'bold italic forecolor | alignleft aligncenter ' +
'alignright alignjustify | bullist numlist outdent indent | ' +
'removeformat | help',
content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:14px }'
}}
/>
<button onClick={log}>Log editor content</button>
</>
);
}
----
+
This JavaScript file will create a component "`+App+`" containing a {productname} editor configured with basic features.
. Update the `+apiKey+` option in the editor element and include your link:{accountsignup}/[{cloudname} API key].
endif::[]
ifeval::["{productSource}" == "package-manager"]
ifeval::["{productUse}" == "host"]
. Install the `+tinymce+`, `+@tinymce/tinymce-react+` and `+fs-extra+` packages.
+
[source,sh]
----
npm install tinymce @tinymce/tinymce-react fs-extra
----
. Setup a `postinstall` script to copy {productname} to the public directory for hosting
+
.postinstall.js
[source,js]
----
import fse from 'fs-extra';
import path from 'path';
const topDir = import.meta.dirname;
fse.emptyDirSync(path.join(topDir, 'public', 'tinymce'));
fse.copySync(path.join(topDir, 'node_modules', 'tinymce'), path.join(topDir, 'public', 'tinymce'), { overwrite: true });
----
+
.package.json
[source,json]
----
{
// ... other content omitted for brevity ...
"scripts": {
// ... other scripts omitted for brevity ...
"postinstall": "node ./postinstall.js"
}
}
----
+
..gitignore
[source,.gitignore]
----
# ... other rules omitted for brevity ...
/public/tinymce/
----
. Run the `postinstall` to copy {productname} to the `public` directory
+
[source,sh]
----
npm run postinstall
----
. Using a text editor, open `+./src/App.jsx+` and replace the contents with:
+
[source,jsx]
----
import { useRef } from 'react';
import { Editor } from '@tinymce/tinymce-react';
import './App.css';
export default function App() {
const editorRef = useRef(null);
const log = () => {
if (editorRef.current) {
console.log(editorRef.current.getContent());
}
};
return (
<>
<Editor
tinymceScriptSrc='/tinymce/tinymce.min.js'
licenseKey='your-license-key'
onInit={(_evt, editor) => editorRef.current = editor}
initialValue='<p>This is the initial content of the editor.</p>'
init={{
height: 500,
menubar: false,
plugins: [
'advlist', 'autolink', 'lists', 'link', 'image', 'charmap',
'anchor', 'searchreplace', 'visualblocks', 'code', 'fullscreen',
'insertdatetime', 'media', 'table', 'preview', 'help', 'wordcount'
],
toolbar: 'undo redo | blocks | ' +
'bold italic forecolor | alignleft aligncenter ' +
'alignright alignjustify | bullist numlist outdent indent | ' +
'removeformat | help',
content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:14px }'
}}
/>
<button onClick={log}>Log editor content</button>
</>
);
}
----
. Update the `+licenseKey+` option in the editor element and include your xref:license-key.adoc[License Key].
endif::[]
ifeval::["{productUse}" == "bundle"]
. Install the `+tinymce+` and `+@tinymce/tinymce-react+` packages
+
[source,sh]
----
npm install tinymce @tinymce/tinymce-react
----
. Using a text editor, create `+./src/BundledEditor.jsx+` and set the contents to:
+
[source,jsx]
----
import { Editor } from '@tinymce/tinymce-react';
// TinyMCE so the global var exists
import 'tinymce/tinymce';
// DOM model
import 'tinymce/models/dom/model'
// Theme
import 'tinymce/themes/silver';
// Toolbar icons
import 'tinymce/icons/default';
// Editor styles
import 'tinymce/skins/ui/oxide/skin';
// importing the plugin js.
// if you use a plugin that is not listed here the editor will fail to load
import 'tinymce/plugins/advlist';
import 'tinymce/plugins/anchor';
import 'tinymce/plugins/autolink';
import 'tinymce/plugins/autoresize';
import 'tinymce/plugins/autosave';
import 'tinymce/plugins/charmap';
import 'tinymce/plugins/code';
import 'tinymce/plugins/codesample';
import 'tinymce/plugins/directionality';
import 'tinymce/plugins/emoticons';
import 'tinymce/plugins/fullscreen';
import 'tinymce/plugins/help';
import 'tinymce/plugins/help/js/i18n/keynav/en';
import 'tinymce/plugins/image';
import 'tinymce/plugins/importcss';
import 'tinymce/plugins/insertdatetime';
import 'tinymce/plugins/link';
import 'tinymce/plugins/lists';
import 'tinymce/plugins/media';
import 'tinymce/plugins/nonbreaking';
import 'tinymce/plugins/pagebreak';
import 'tinymce/plugins/preview';
import 'tinymce/plugins/quickbars';
import 'tinymce/plugins/save';
import 'tinymce/plugins/searchreplace';
import 'tinymce/plugins/table';
import 'tinymce/plugins/visualblocks';
import 'tinymce/plugins/visualchars';
import 'tinymce/plugins/wordcount';
// importing plugin resources
import 'tinymce/plugins/emoticons/js/emojis';
// Content styles, including inline UI like fake cursors
import 'tinymce/skins/content/default/content';
import 'tinymce/skins/ui/oxide/content';
export default function BundledEditor(props) {
return (
<Editor
licenseKey='your-license-key'
{...props}
/>
);
}
----
. Update the `+licenseKey+` option in the editor element and include your xref:license-key.adoc[License Key].
. Using a text editor, open `+./src/App.jsx+` and replace the contents with:
+
[source,jsx]
----
import { useRef } from 'react';
import BundledEditor from './BundledEditor'
import './App.css';
export default function App() {
const editorRef = useRef(null);
const log = () => {
if (editorRef.current) {
console.log(editorRef.current.getContent());
}
};
return (
<>
<BundledEditor
onInit={(_evt, editor) => editorRef.current = editor}
initialValue='<p>This is the initial content of the editor.</p>'
init={{
height: 500,
menubar: false,
plugins: [
'advlist', 'anchor', 'autolink', 'help', 'image', 'link', 'lists',
'searchreplace', 'table', 'wordcount'
],
toolbar: 'undo redo | blocks | ' +
'bold italic forecolor | alignleft aligncenter ' +
'alignright alignjustify | bullist numlist outdent indent | ' +
'removeformat | help',
content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:14px }'
}}
/>
<button onClick={log}>Log editor content</button>
</>
);
}
----
endif::[]
endif::[]
ifeval::["{productSource}" == "zip"]
ifeval::["{productUse}" == "host"]
. Install the `+@tinymce/tinymce-react+` package.
[source,sh]
----
npm install @tinymce/tinymce-react
----
. Unzip the content of the `+tinymce/js+` folder from the link:{download-enterprise}[{productname} zip] into the `+public+` folder. Afterwards the directory listing should be similar to below:
+
.> `tree -L 2 public`
[source,text]
----
public
├── favicon.ico
├── index.html
├── logo192.png
├── logo512.png
├── manifest.json
├── robots.txt
└── tinymce
├── icons
├── langs
├── license.txt
├── models
├── plugins
├── skins
├── themes
├── tinymce.d.ts
└── tinymce.min.js
----
. Using a text editor, open `+./eslint.config.js` and add `+'src/tinymce'+` to the `+ignores+` array.
+
.Diff of `.eslint.config.js`
[source,patch]
----
export default tseslint.config(
- { ignores: ['dist'] },
+ { ignores: ['dist', 'src/tinymce'] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ['**/*.{ts,tsx}'],
----
. Using a text editor, open `+./src/App.jsx+` and replace the contents with:
+
[source,jsx]
----
import { useRef } from 'react';
import { Editor } from '@tinymce/tinymce-react';
import './App.css';
export default function App() {
const editorRef = useRef(null);
const log = () => {
if (editorRef.current) {
console.log(editorRef.current.getContent());
}
};
return (
<>
<Editor
tinymceScriptSrc='/tinymce/tinymce.min.js'
licenseKey='your-license-key'
onInit={(_evt, editor) => editorRef.current = editor}
initialValue='<p>This is the initial content of the editor.</p>'
init={{
height: 500,
menubar: false,
plugins: [
'advlist', 'autolink', 'lists', 'link', 'image', 'charmap',
'anchor', 'searchreplace', 'visualblocks', 'code', 'fullscreen',
'insertdatetime', 'media', 'table', 'preview', 'help', 'wordcount'
],
toolbar: 'undo redo | blocks | ' +
'bold italic forecolor | alignleft aligncenter ' +
'alignright alignjustify | bullist numlist outdent indent | ' +
'removeformat | help',
content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:14px }'
}}
/>
<button onClick={log}>Log editor content</button>
</>
);
}
----
. Update the `+licenseKey+` option in the editor element and include your xref:license-key.adoc[License Key].
endif::[]
ifeval::["{productUse}" == "bundle"]
. Install the `+@tinymce/tinymce-react+` and `+script-loader+` packages.
+
[source,sh]
----
npm install @tinymce/tinymce-react script-loader
----
. Unzip the content of the `+tinymce/js+` folder from the link:{download-enterprise}[{productname} zip] into the `+src+` folder. Afterwards the directory listing should be similar to below:
+
.> `tree -L 2 src`
[source,text]
----
src
├── App.css
├── App.js
├── App.test.js
├── index.css
├── index.js
├── logo.svg
├── reportWebVitals.js
├── setupTests.js
└── tinymce
├── icons
├── langs
├── license.txt
├── models
├── plugins
├── skins
├── themes
├── tinymce.d.ts
└── tinymce.min.js
----
. Using a text editor, open `+./eslint.config.js+` and add `+'src/tinymce'+` to the `+ignores+` array.
+
.Diff of `.eslint.config.js`
[source,patch]
----
diff --git a/eslint.config.js b/eslint.config.js
index 092408a..1ab8db4 100644
--- a/eslint.config.js
+++ b/eslint.config.js
@@ -5,7 +5,7 @@ import reactRefresh from 'eslint-plugin-react-refresh'
import tseslint from 'typescript-eslint'
export default tseslint.config(
- { ignores: ['dist'] },
+ { ignores: ['dist', 'src/tinymce'] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ['**/*.{ts,tsx}'],
----
. Using a text editor, create `+./src/BundledEditor.jsx+` and set the contents to:
+
[source,jsx]
----
import { Editor } from '@tinymce/tinymce-react';
// TinyMCE so the global var exists
import './tinymce/tinymce.min.js';
// DOM model
import './tinymce/models/dom/model.min.js'
// Theme
import './tinymce/themes/silver/theme.min.js';
// Toolbar icons
import './tinymce/icons/default/icons.min.js';
// Editor styles
import './tinymce/skins/ui/oxide/skin.min.js';
// importing the plugin index.js file.
// if you use a plugin that is not listed here the editor will fail to load
import './tinymce/plugins/advlist';
import './tinymce/plugins/anchor';
import './tinymce/plugins/autolink';
import './tinymce/plugins/autoresize';
import './tinymce/plugins/autosave';
import './tinymce/plugins/charmap';
import './tinymce/plugins/code';
import './tinymce/plugins/codesample';
import './tinymce/plugins/directionality';
import './tinymce/plugins/emoticons';
import './tinymce/plugins/fullscreen';
import './tinymce/plugins/help';
import './tinymce/plugins/image';
import './tinymce/plugins/importcss';
import './tinymce/plugins/insertdatetime';
import './tinymce/plugins/link';
import './tinymce/plugins/lists';
import './tinymce/plugins/media';
import './tinymce/plugins/nonbreaking';
import './tinymce/plugins/pagebreak';
import './tinymce/plugins/preview';
import './tinymce/plugins/quickbars';
import './tinymce/plugins/save';
import './tinymce/plugins/searchreplace';
import './tinymce/plugins/table';
import './tinymce/plugins/visualblocks';
import './tinymce/plugins/visualchars';
import './tinymce/plugins/wordcount';
// importing plugin resources
import './tinymce/plugins/emoticons/js/emojis.js';
// Content styles, including inline UI like fake cursors
import './tinymce/skins/content/default/content.js';
import './tinymce/skins/ui/oxide/content.js';
export default function BundledEditor(props) {
return (
<Editor
licenseKey='your-lisense-key'
{...props}
/>
);
}
----
. Update the `+licenseKey+` option in the editor element and include your xref:license-key.adoc[License Key].
. Using a text editor, open `+./src/App.jsx+` and replace the contents with:
+
[source,jsx]
----
import { useRef } from 'react';
import BundledEditor from './BundledEditor'
import './App.css';
export default function App() {
const editorRef = useRef(null);
const log = () => {
if (editorRef.current) {
console.log(editorRef.current.getContent());
}
};
return (
<>
<BundledEditor
onInit={(_evt, editor) => editorRef.current = editor}
initialValue='<p>This is the initial content of the editor.</p>'
init={{
height: 500,
menubar: false,
plugins: [
'advlist', 'anchor', 'autolink', 'help', 'image', 'link', 'lists',
'searchreplace', 'table', 'wordcount'
],
toolbar: 'undo redo | blocks | ' +
'bold italic forecolor | alignleft aligncenter ' +
'alignright alignjustify | bullist numlist outdent indent | ' +
'removeformat | help',
content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:14px }'
}}
/>
<button onClick={log}>Log editor content</button>
</>
);
}
----
endif::[]
endif::[]
. Test the application using the Node.js development server.
+
* To start the development server, navigate to the `+tinymce-react-demo+` directory and run:
+
[source,sh]
----
npm run dev
----
* To stop the development server, select on the command line or command prompt and press _Ctrl+C_.
== Deploying the application to a HTTP server
The application will require further configuration before it can be deployed to a production environment. For information on configuring the application for deployment, see: https://vitejs.dev/guide/build[Building for Production] or https://vitejs.dev/guide/static-deploy.html[Deploying a Static Site].
To deploy the application to a local HTTP Server:
. Navigate to the `+tinymce-react-demo+` directory and run:
+
[source,sh]
----
npm run build
----
. You can optionally preview the production build by running:
+
[source,sh]
----
npm run preview
----
. Copy the contents of the `+tinymce-react-demo/dist+` directory to the root directory of the web server.
The application has now been deployed on the web server.
NOTE: Additional configuration is required to deploy the application outside the web server root directory, such as +http://localhost:<port>/my_react_application+.
== Next Steps
ifeval::["{productUse}" == "bundle"]
* For information on bundling, see: xref:introduction-to-bundling-tinymce.adoc[]
endif::[]
* For examples of the {productname} integration, see: https://tinymce.github.io/tinymce-react/[the tinymce-react storybook].
* For information on customizing:
** {productname} integration, see: xref:react-ref.adoc[].
** {productname}, see: xref:basic-setup.adoc[].
** The React application, see: https://vitejs.dev/guide/#getting-started[Getting Started with Vite] or https://react.dev/learn[the React documentation].