Days
Hours
Minutes
Seconds
x
Skip to content
Froala Documentation

Migrating from TinyMCE to Froala Editor

This guide walks you through migrating your existing TinyMCE integration to Froala Editor. Each section maps a TinyMCE concept directly to its Froala equivalent, with side-by-side code examples so you can update your project quickly and confidently.

Before You Begin

Make sure you have a valid Froala license key. You can start a free trial or purchase a license.

If you need help during migration, reach out to the Froala support team.

Why Migrate to Froala?

Froala Editor is a lightweight, fast, and developer-friendly WYSIWYG editor.

Cost and licensing is where Froala has the most significant advantage over TinyMCE. TinyMCE’s paid plans cap the number of editor loads per month and charge overage fees when you exceed that limit. Those costs compound quickly in any product with real user traffic. Froala’s plans include unlimited editor loads and unlimited active users on every tier, with no overage charges. See the full Froala vs. TinyMCE comparison.

Beyond pricing, Froala also offers:

  • Fast initialization: loads swiftly.
  • Clean HTML output: semantic markup
  • Modern UI: a polished, responsive toolbar your users will love.
  • Framework SDKs: native packages for React, Vue, Angular, and 15+ other frameworks.
  • Simple API: fewer concepts to learn, less code to write.
 

Remove TinyMCE and Add Froala

1. For Tiny Cloud deployments

Remove TinyMCE source script from your project.
<!-- TinyMCE via CDN -->
<script src="https://cloud.tinymce.com/stable/tinymce.min.js?apiKey=YOUR_API_KEY"></script>
Add Froala stylesheet and script tags to your HTML:
<!-- In <head>: CSS stylesheets-->

<link href="https://cdn.jsdelivr.net/npm/froala-editor@latest/css/froala_editor.pkgd.min.css"
rel="stylesheet" type="text/css" />
<link href="https://cdn.jsdelivr.net/npm/froala-editor@latest/css/froala_style.min.css"
rel="stylesheet" type="text/css" />

<!-- Before </body>: JS -->
<script src="https://cdn.jsdelivr.net/npm/froala-editor@latest/js/froala_editor.pkgd.min.js"
type="text/javascript"></script>

2. For self-hosted TinyMCE deployments

Remove TinyMCE source script from your project.
<script src="/path/to/tinymce/base/directory/tinymce.min.js"></script>
Add Froala stylesheet and script tags to your HTMLand end of:
<!-- In <head>: CSS stylesheets-->

<link href="/path/to/froala/base/directory/css/froala_editor.pkgd.min.css"
rel="stylesheet" type="text/css" />
<link href="/path/to/froala/base/directory/css/froala_style.min.css"
rel="stylesheet" type="text/css" />

<!-- Before </body>: JS -->
<script src="/path/to/froala/base/directory/js/froala_editor.pkgd.min.js"
type="text/javascript"></script>

3. For NPM deployments:

Remove the TinyMCE NPM packages from your environment:
npm uninstall -g tinymce
Remove TinyMCE NPM link.
<script type="text/javascript" src="/usr/local/lib/node_modules/tinymce/tinymce.min.js"></script>
Install Froala:
npm install froala-editor
Add Froala NPM links.
See Installation Guides for other Froala installation methods.

Basic Initialization

TinyMCE

<textarea id="editor">Hello, World!</textarea>

<script>
tinymce.init({
selector: '#editor'
});
</script>

Froala

<div id="editor">Hello, World!</div>

<script>
new FroalaEditor('#editor', {
key: 'YOUR_LICENSE_KEY'
});
</script>

Configuration Options

Toolbar

Control which buttons appear in the editor toolbar. TinyMCE
tinymce.init({
  selector: '#editor',
  toolbar: 'undo redo | bold italic underline | alignleft aligncenter alignright | bullist numlist'
});
Froala
new FroalaEditor('#editor', {
  toolbarButtons: [
    'undo', 'redo', '|',
    'bold', 'italic', 'underline', '|',
    'alignLeft', 'alignCenter', 'alignRight', '|',
    'formatUL', 'formatOL'
  ]
});
Note: Froala offers options for customizing toolbar based on screen size. See this toolbar customization guide for more details.

Placeholder Text

TinyMCE
tinymce.init({
  selector: '#editor',
  placeholder: 'Start typing here...'
});
Froala
new FroalaEditor('#editor', {
  placeholderText: 'Start typing here...'
});
Key difference: TinyMCE uses placeholder. Froala uses placeholderText.

Read-Only Mode

TinyMCE
tinymce.init({
  selector: '#editor',
  readonly: true
});
Froala
new FroalaEditor('#editor', {});

// Toggle read-only dynamically:
editor.edit.off(); // enables read-only
editor.edit.on();  // disables read-only
Key difference: TinyMCE sets read-only at init time via readonly: true. Froala uses the methods editor.edit.off() and editor.edit.on() to toggle read-only dynamically at any time.

Height and Width

TinyMCE
tinymce.init({
  selector: '#editor',
  height: 400,
  width: 800
});
Froala
new FroalaEditor('#editor', {
  height: 400,
  width: 800
});

Content Styling

Apply custom CSS to the editable content area. TinyMCE
tinymce.init({
  selector: '#editor',
  content_css: '/path/to/custom-content.css'
});
Froala
new FroalaEditor('#editor', {
  // Inject inline styles into the editable area
  editorClass: 'my-custom-editor-class'
});
Or link an external stylesheet with the iframe option:
new FroalaEditor('#editor', {
  iframeStyle: 'body { font-family: Arial; color: #333; }'
});
Key difference: TinyMCE links a CSS file via content_css. Froala applies a CSS class via editorClass, or injects styles directly with iframeStyle.

Plugins

TinyMCE activates plugins by listing them in the plugins
option. Froala ships most features as built-in plugins and loads them automatically when you include froala_editor.pkgd.min.js.
You can also load plugins individually.

TinyMCE

tinymce.init({
  selector: '#editor',
  plugins: 'lists link image table code'
});

Froala — Load All Plugins (Recommended)

<!-- Includes all plugins bundled -->
<script src="https://cdn.jsdelivr.net/npm/froala-editor@latest/js/froala_editor.pkgd.min.js"></script>

Froala — Load Individual Plugins

<!-- Core editor only -->
<script src="https://cdn.jsdelivr.net/npm/froala-editor@latest/js/froala_editor.min.js"></script>
 
<!-- Add only what you need -->
<script src="https://cdn.jsdelivr.net/npm/froala-editor@latest/js/plugins/lists.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/froala-editor@latest/js/plugins/link.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/froala-editor@latest/js/plugins/image.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/froala-editor@latest/js/plugins/table.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/froala-editor@latest/js/plugins/code_view.min.js"></script>

Then enable or disable them in your code.

new FroalaEditor('#editor', {
  pluginsEnabled: ['image', 'link'],
  pluginsDisabled: ['lists'],
});

Events

TinyMCE

tinymce.init({
  selector: '#editor',
  setup: function (editor) {
    editor.on('change', function () {
      console.log('Content changed:', editor.getContent());
    });
    editor.on('init', function () {
      console.log('Editor is ready!');
    });
    editor.on('focus', function () {
      console.log('Editor focused.');
    });
    editor.on('blur', function () {
      console.log('Editor blurred.');
    });
  }
});

Froala

new FroalaEditor('#editor', {
  events: {
    'contentChanged': function () {
      console.log('Content changed:', this.html.get());
    },
    'initialized': function () {
      console.log('Editor is ready!');
    },
    'focus': function () {
      console.log('Editor focused.');
    },
    'blur': function () {
      console.log('Editor blurred.');
    }
  }
});

Key difference: TinyMCE uses a setup
callback where you attach events with editor.on().
Froala accepts an events
object directly in the config. Inside Froala event callbacks, this
refers to the editor instance, giving you direct access to the full API.

Methods

Getting and Setting Content

TinyMCE
// Get content
const content = tinymce.get('editor').getContent();

// Set content
tinymce.get('editor').setContent('<p>New content</p>');
Froala
// Store the editor instance at init
const editor = new FroalaEditor('#editor', { /* options */ });

// Get content
const content = editor.html.get();

// Set content
editor.html.set('<p>New content</p>');

Destroy and Re-initialize

TinyMCE
// Destroy
tinymce.get('editor').remove();

// Re-initialize
tinymce.init({ selector: '#editor' });
Froala
// Destroy
editor.destroy();

// Re-initialize
const editor = new FroalaEditor('#editor', { /* options */ });

Focus and Blur

TinyMCE
tinymce.get('editor').focus();
Froala
editor.events.focus();
editor.events.blur();

Insert HTML at Cursor

TinyMCE
tinymce.get('editor').insertContent('<strong>Inserted text</strong>');
Froala
editor.html.insert('<strong>Inserted text</strong>');

Undo / Redo

TinyMCE
tinymce.get('editor').execCommand('undo');
tinymce.get('editor').execCommand('redo');
Froala
editor.commands.undo();
editor.commands.redo();
For a complete list of methods, refer to the methods API documentation.

Image Upload

TinyMCE
tinymce.init({
  selector: '#editor',
  plugins: 'image',
  images_upload_url: '/api/upload-image',
  images_upload_handler: function (blobInfo, success, failure) {
    const formData = new FormData();
    formData.append('file', blobInfo.blob(), blobInfo.filename());

    fetch('/api/upload-image', {
      method: 'POST',
      body: formData
    })
    .then(res => res.json())
    .then(data => success(data.location))
    .catch(() => failure('Upload failed'));
  }
});
Froala
new FroalaEditor('#editor', {
  imageUploadURL: '/api/upload-image',
  imageUploadMethod: 'POST',
  imageUploadParam: 'file',
  events: {
    'image.uploaded': function (response) {
      // response is the raw server response string
      console.log('Image uploaded:', response);
    },
    'image.error': function (error) {
      console.error('Upload error:', error);
    }
  }
});
Key difference: Froala handles the upload form construction for you. Point imageUploadURL at your endpoint and Froala sends a multipart/form-data POST automatically. Your server should return a JSON object like { "link": "/path/to/image.jpg" }.

Framework Integration

React

TinyMCE
import { Editor } from '@tinymce/tinymce-react';

function MyEditor() {
  return (
    <Editor
      apiKey="YOUR_API_KEY"
      initialValue="<p>Hello World</p>"
      init={{
        height: 400,
        plugins: 'lists link image',
        toolbar: 'bold italic | bullist numlist'
      }}
      onEditorChange={(content) => console.log(content)}
    />
  );
}
Froala
import 'froala-editor/css/froala_style.min.css';
import 'froala-editor/css/froala_editor.pkgd.min.css';
import 'froala-editor/js/plugins.pkgd.min.js';
import FroalaEditorComponent from 'react-froala-wysiwyg';

function MyEditor() {
  const config = {
    key: 'YOUR_LICENSE_KEY',
    heightMin: 400,
    placeholderText: 'Start writing...',
    events: {
      contentChanged: function () {
        console.log(this.html.get());
      }
    }
  };

  return (
    <FroalaEditorComponent
      tag="textarea"
      config={config}
    />
  );
}

export default MyEditor;
Install:
npm install react-froala-wysiwyg froala-editor

Vue.js

TinyMCE
<template>
  <Editor
    api-key="YOUR_API_KEY"
    v-model="content"
    :init="{ height: 400, plugins: 'lists link' }"
  />
</template>

<script>
import { Editor } from '@tinymce/tinymce-vue';
export default {
  components: { Editor },
  data() {
    return { content: '<p>Hello World</p>' };
  }
};
</script>
Froala
<template>
  <froala
    :tag="'textarea'"
    :config="config"
    v-model:value="content"
  />
</template>

<script>
import 'froala-editor/js/plugins.pkgd.min.js';
import 'froala-editor/css/froala_editor.pkgd.min.css';
import 'froala-editor/css/froala_style.min.css';

export default {
  data() {
    return {
      content: '<p>Hello World</p>',
      config: {
        key: 'YOUR_LICENSE_KEY',
        heightMin: 400,
        placeholderText: 'Start writing...'
      }
    };
  }
};
</script>
Install:
npm install vue-froala-wysiwyg froala-editor
In main.js:
import VueFroala from 'vue-froala-wysiwyg';
app.use(VueFroala);

Angular

TinyMCE
// app.module.ts
import { EditorModule } from '@tinymce/tinymce-angular';

@NgModule({
  imports: [EditorModule]
})
<!-- component template -->
<editor
  apiKey="YOUR_API_KEY"
  [(ngModel)]="content"
  [init]="{ height: 400, plugins: 'lists link' }">
</editor>
Froala
// app.module.ts
import { FroalaEditorModule, FroalaViewModule } from 'angular-froala-wysiwyg';

@NgModule({
  imports: [
    FroalaEditorModule.forRoot(),
    FroalaViewModule.forRoot()
  ]
})
<!-- component template -->
<div
  [froalaEditor]="editorOptions"
  [(froalaModel)]="content">
</div>
// component.ts
editorOptions = {
  key: 'YOUR_LICENSE_KEY',
  heightMin: 400,
  placeholderText: 'Start writing...'
};
content = '<p>Hello World</p>';
Install:
npm install angular-froala-wysiwyg froala-editor

Still Have Questions?

Here are some additional resources if you can’t find an answer you need.