Start trial
Plans & PricingContact Us
Log InStart For Free

How to integrate React with TinyMCE

March 26th, 2017

6 min read

React and Tiny MCE

Written by

Team Tiny

Category

Developer Insights

For TinyMCE 5: See how to add TinyMCE 5 to a simple React project.

After the roaring success of our Angular 2 and TinyMCE article, I am back to show you how to create a similar functioning piece of code. This time, using the React library. If you have already read the Angular 2 version, most of this will be familiar territory. Even so, I hope you will still have fun following along.

Prerequisites

This will not be a particularly advanced blog post, technically speaking, but I do expect you to have a working understanding of:

  • JavaScript (including some of the newer, es2015 features)
  • React
  • How to use the terminal/command line

I also assume that you have Node and npm installed on your computer. We will write our code with the newest ES2015 syntax, which will be transpiled down to more browser friendly JavaScript by Babel in our build step. If all of this sounds scary and complicated, it really isn’t.

Setting up

Setting up a new project can be a very daunting process. Just as in the Angular 2 post, we will be using a marvelous tool that takes care of most setup for us. Meet create-react-app.

As you will soon see, using create-react-app makes the first setup process extremely easy and quick, but using create-react-app is optional to follow along in this tutorial. If you already have a project setup that you want to use you should be able to follow along with this guide – although you might have to solve some ‘gotchas’ and problems on your own that create-react-app takes care of otherwise.

Anyway, to start off we will install the create-react-app tool with the following command:

npm install create-react-app --global

After some installing, you now have the create-react-app command available in your terminal, so let’s start using it!

Creating the project

Using create-react-app, we will create a new project using the following command:

create-react-app tiny-react

Where tiny-react is simply the name of the folder the project will be generated into, you could also just write create-react-app . (Note: That’s a single period at the end to generate the project in the current directory.)

After the project has been generated and all the dependencies has been installed, just cd into the project directory:

cd tiny-react

If you are using git for your version control (if not … why?) this might also be a perfect time to initialize a repository in the project directory and commit all the files so you have something to reset to if you mess something up later on.

git init
git add --all
git commit -m ‘initial commit’

Installing TinyMCE

The next step is to install TinyMCE into our project, which we simply do with npm and the following command:

npm install tinymce --save

After that has finished installing we are ready to start writing some code, so open up the project directory in your IDE/editor of choice.

Getting the skin

For the TinyMCE editor to work it needs a skin, which simply consists of font and CSS files used by the editor. The most straightforward way to get these files to the correct place in a project generated by create-react-app is to copy them from the tinymce directory in the node_modules to the public directory in the root of your project (it was created by create-react-app). Anything in this public directory will be moved to the build directory by the build step provided by create-react-app, and an environment variable called PUBLIC_URL is available to get the absolute url to the public files (the environment variable is replaced by the build step and won’t show up in the built code).

How you do the copying is up to you, either manually using the file explorer/finder, or with a terminal command looking something like this:

Macos and Linux:

cp -r node_modules/tinymce/skins public/skins

Windows

xcopy /I /E node_modules/tinymce/skins src/assets/skins

Then later, when initializing a TinyMCE instance, just add the skin_url setting with the url like this:

tinymce.init({
  // other settings...
  skin_url: `${process.env.PUBLIC_URL}/skins/lightgray`,
  // … more settings
});

create-react-app will then take care of all the other stuff for you, making sure it works in both development and production.

Creating a simple TinyEditorComponent

Now, let’s finally get started writing some code!

Create a new directory in the src directory called components and create a file called TinyEditorComponent.js in that directory.

In this file, let’s start by creating a simple component that only returns a paragraph with the text “Hello World” in it, with the code looking something like this:

import React, { Component } from "react";

class TinyEditorComponent extends Component {
  render() {
    return <p>Hello World</p>;
  }
}

export default TinyEditorComponent;

And then add the component to the App.js file in the source directory, changing the code to look something like this:

import React, { Component } from "react";
import logo from "./logo.svg";
import "./App.css";

import TinyEditorComponent from "./components/TinyEditorComponent";

class App extends Component {
  render() {
    return (
      <div className="App">
        <div className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h2>Welcome to React</h2>
        </div>
        <TinyEditorComponent />
      </div>
    );
  }
}

export default App;

What we are doing here is simply importing the TinyEditorComponent into the App.js file and then adding it to our app with the JSX syntax. If you start the development server with npm start now you should see the text “Hello World” underneath the spinning React logo. Success! Now let’s get on with adding tinymce to the mix.

More code

I will start by adding all of the code in the TinyEditorComponent first and then go through it bit by bit underneath.

TinyEditorComponent.js

import React, { Component } from "react";
import tinymce from "tinymce";
import "tinymce/themes/modern";
import "tinymce/plugins/wordcount";
import "tinymce/plugins/table";

class TinyEditorComponent extends Component {
  constructor() {
    super();
    this.state = { editor: null };
  }

  componentDidMount() {
    tinymce.init({
      selector: `#${this.props.id}`,
      skin_url: `${process.env.PUBLIC_URL}/skins/lightgray`,
      plugins: "wordcount table",
      setup: (editor) => {
        this.setState({ editor });
        editor.on("keyup change", () => {
          const content = editor.getContent();
          this.props.onEditorChange(content);
        });
      },
    });
  }

  componentWillUnmount() {
    tinymce.remove(this.state.editor);
  }

  render() {
    return (
      <textarea
        id={this.props.id}
        value={this.props.content}
        onChange={(e) => console.log(e)}
      />
    );
  }
}

export default TinyEditorComponent;

If we start with the beginning we simply have the import statements:

import React, { Component } from "react";
import tinymce from "tinymce";
import "tinymce/themes/modern";
import "tinymce/plugins/wordcount";
import "tinymce/plugins/table";

First, we import React (and destructure out Component for a cleaner class syntax later), then tinymce. A theme is also needed for the editor to work so I import the modern theme underneath. Any plugin that you want to include will also have to be imported similarly. In this example, I am including the Word Count and Table plugins.

Next, let’s jump into the component class itself and start with the constructor:

constructor() {
    super();
    this.state = { editor: null };
}

Not that much to talk about here, we are only setting up the initial state to null to be as clear as possible with the fact that this component will be stateful. I think you could just skip the constructor and just set the state anyway, but let’s be as straightforward with the state as possible.

The next method is the componentDidMount lifecycle hook:

componentDidMount() { 
   tinymce.init({ 
      selector: `#${this.props.id}`, 
      skin_url: `${process.env.PUBLIC_URL}/skins/lightgray`, 
      plugins: 'wordcount table', 
      setup: editor => { 
        this.setState({ editor }); 
        editor.on('keyup change', () => { 
           const content = editor.getContent(); 
           this.props.onEditorChange(content); 
        }); 
      } 
   }); 
}

Here, we will initialize the TinyMCE editor, with the selector set to the id prop that is passed down from the parent component. At this point, the skin_url setting will be set to the public folder with the environment variable as previously explained, the two plugins that we imported are added to the plugins setting, and the setup function setting up both states – that is, say saving a reference to the TinyMCE editor for later cleanup purposes. We are also adding the event handlers for the keyup and change events in the editor to call the onEditorChange prop callback function passed in from the parent component with the editor content.

Next up, is the componentWillUnmount lifecycle hook:

componentWillUnmount() { 
  tinymce.remove(this.state.editor); 
}

This is pretty self-explanatory. It simply removes the editor when the component is unmounted (removed from the page) using the reference to the editor instance we saved in the component’s state.

Last but not least, we have the render function:

render() { 
    return ( <textarea id="{this.props.id}" /> ); 
}

This shouldn’t take that much explanation either. We simply render a textarea with the id set to the id prop sent in from the parent component. We also have the defaultValue set to the ‘this.props.’ content, making it possible to initialize the editor with content in it.

If we now go back to the App.js file and change the TinyEditorComponent JSX to add some props like this:

<TinyEditorComponent
  id="myCoolEditor"
  onEditorChange={(content) => console.log(content)}
/>;

Save and start up the development server again (or just wait for it to automatically reload if you left it running), and you should see a TinyMCE editor underneath the spinning React logo. Type something into the editor and you should see it being logged out in the browser console. Yay!

Wrapping up

Hopefully, you found this blog post valuable and entertaining. I also hope it is leaving you with some kind of hunger to start using TinyMCE in your future React applications. If you’re building something for a customer, consider signing up for our cloud plans to get more out of TinyMCE. If you have questions, feel free to comment below or post in our Community forum.

Have fun hacking!

Bonus material

Tired of the spinning React logo on the standard page that create-react-att generated? Open up the logo.svg file in the src directory and replace its contents with the following:

<svg viewBox="0 0 225.000000 199.000000">
    <g transform="translate(0.000000,199.000000) scale(0.100000,-0.100000)" fill="#4775ce">
      <path d="M551 1416 l-552 -552 31 -29 31 -29 62 62 62 62 460 -460 460 -460
      559 552 558 552 -26 23 c-15 13 -32 23 -37 23 -6 0 -34 -23 -64 -51 -30 -28
      -58 -49 -64 -47 -5 1 -216 206 -468 455 l-460 452 -552 -553z m984 -856 l-430
      -430 -430 430 -430 430 430 430 430 430 430 -430 430 -430 -430 -430z"/>
      <path d="M900 1250 l0 -40 220 0 220 0 0 40 0 40 -220 0 -220 0 0 -40z"/>
      <path d="M740 1070 l0 -40 370 0 370 0 0 40 0 40 -370 0 -370 0 0 -40z"/>
      <path d="M740 890 l0 -40 370 0 370 0 0 40 0 40 -370 0 -370 0 0 -40z"/>
      <path d="M900 710 l0 -40 220 0 220 0 0 40 0 40 -220 0 -220 0 0 -40z"/>
    </g>
</svg>

Then, a spinning TinyMCE logo appears! So much nicer! 🙂

Stuck on the App.js code?

import React, { Component } from "react";
import logo from "./logo.svg";
import "./App.css";

import TinyEditorComponent from "./components/TinyEditorComponent";

class App extends Component {
  render() {
    return (
      <div className="App">
        <div className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h2>Welcome to React + TinyMCE</h2>
        </div>
        <TinyEditorComponent
          id="myCoolEditor"
          onEditorChange={(content) => console.log(content)}
        />
      </div>
    );
  }
}

export default App;
ReactIntegration
byTeam Tiny

Powering more than 40% of the world’s websites. Here to educate and empower the world through all things TinyMCE and more.

Related Articles

  • Developer InsightsNov 7th, 2024

    Meet the Top Experts at Frontend Nation 2024 with TinyMCE

Join 100,000+ developers who get regular tips & updates from the Tiny team.

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Tiny logo

Stay Connected

SOC2 compliance badge

Products

TinyMCEDriveMoxieManager
© Copyright 2024 Tiny Technologies Inc.

TinyMCE® and Tiny® are registered trademarks of Tiny Technologies, Inc.