Upgrade TinyMCE to v6 in Rails/Stimulus

djchadderton - Feb 11 '23 - - Dev Community

A couple of years ago, I wrote a post on how to integrate the text editor TinyMCE into a Rails app using Stimulus.

While most of that post is still relevant, even after upgrading to Rails 7 and replacing Webpack with esbuild, the upgrade from v5 to v6 of TinyMCE did break a few things, so here's how to get it working again.

First of all, add the upgraded version to package.json by changing

"tinymce": "^5.8.0"
Enter fullscreen mode Exit fullscreen mode

to

"tinymce": "^6.3.0"
Enter fullscreen mode Exit fullscreen mode

and run the yarn command to update it.

In the Stimulus controller, as well as importing tinymce, you need to import the model, so the start of the controller file will read

import { Controller } from '@hotwired/stimulus'

// Import TinyMCE
import tinymce from 'tinymce/tinymce'
import 'tinymce/models/dom/model'
Enter fullscreen mode Exit fullscreen mode

Some plugins have been removed or incorporated into the main bundle, so delete any import statements for bbcode, colorpicker, contextmenu, fullpage, hr, imagetools, legacyoutput, noneditable, paste, print, spellchecker, tabfocus, textcolor, textpattern, toc.

Within your toolbar entries, rename styleselect to style, e.g.

toolbar: ['styles | bold italic underline strikethrough superscript | blockquote numlist bullist link | alignleft aligncenter alignright | table']
Enter fullscreen mode Exit fullscreen mode

Some other options have changed, so check the documentation on Migrating from TinyMCE 5 to TinyMCE 6 on the TinyMCE web site if anything isn't working as expected.

My current working Stimulus controller in full is:

import { Controller } from '@hotwired/stimulus'

// Import TinyMCE
import tinymce from 'tinymce/tinymce'
import 'tinymce/models/dom/model'

// Import icons
import 'tinymce/icons/default/icons'

// Import theme
import 'tinymce/themes/silver/theme'

// Import plugins

// 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/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/template'
// import 'tinymce/plugins/visualblocks'
// import 'tinymce/plugins/visualchars'
import 'tinymce/plugins/wordcount'

export default class extends Controller {
  static targets = ['input']

  initialize () {
    this.defaults = {
      autoresize_bottom_margin: 10,
      browser_spellcheck: true,
      content_css: false,
      content_style: `
        html {
          font-family: Roboto, sans-serif; line-height: 1.5;
        }
        h3, h4 {
          font-family: 'Montserrat', sans-serif;
          color: hsla(197, 55%, 26%, 1);
          line-height: 1;
          margin: .9rem 0;
        }
        `,
      invalid_elements: 'span',
      link_context_toolbar: true,
      link_default_target: '_blank',
      link_title: false,
      max_height: 700,
      menubar: false,
      mobile: {
        toolbar: [
          'styles | bold italic underline strikethrough superscript',
          'blockquote numlist bullist link | alignleft aligncenter alignright | table',
          'undo redo | fullscreen preview code help'
        ]
      },
      plugins: 'link lists fullscreen help preview table code autoresize wordcount',
      relative_urls: false,
      skin: false,
      style_formats: [
          { title: 'Heading', format: 'h3' },
          { title: 'Sub Heading', format: 'h4' },
          { title: 'Sub Heading 2', format: 'h5' },
          { title: 'Sub Heading 3', format: 'h6' },
          { title: 'Paragraph', format: 'p'}
      ],
      toolbar: [
        'styles | bold italic underline strikethrough superscript | blockquote numlist bullist link | alignleft aligncenter alignright | table',
        'undo redo | fullscreen preview code help'
              ],
      valid_styles: { '*': 'text-align' }
    }
  }

  connect () {
    // Initialize TinyMCE
    if (!this.preview) {
      let config = Object.assign({ target: this.inputTarget }, this.defaults)
      this.tc = tinymce.init(config)
    }
  }

  disconnect () {
    if (!this.preview) tinymce.remove(this.tc.id)
  }

  get preview () {
    return document.documentElement.hasAttribute('data-turbo-preview')
  }
}
Enter fullscreen mode Exit fullscreen mode

Additional note for upgrading to v7

TinyMCE version 7 has added an extra requirement to specify either the open source GPLv2+ or a commercial licence in the config options object or it will warn in the console that it is running in evaluation mode. Add the following to this.defaults to continue using the open source version:

license_key: "gpl",
Enter fullscreen mode Exit fullscreen mode
. . . . . .