Search code examples
javascriptvue.jstinymcenuxt.jsscript-tag

How to use TinyMCE in Nuxt?


I want to add this script to my Nuxt code:

<script>
  tinymce.init({
    selector: "#mytextarea",
    plugins: "emoticons",
    toolbar: "emoticons",
    toolbar_location: "bottom",
    menubar: false
  });
</script>

I can just throw it into my component's template body (This script has to be inside <body> not <head>) like this:

enter image description here

and interestingly enough it works but there are two issues here:

  1. It looks ugly
  2. It's not dynamic. For example I can't bind selector dynamically to a prop or a data property! It has to be hardcoded.

So I was wondering if anybody knows how can I integrate such scripts into my Nuxt project properly?


Solution

    1. I really really doubt this works. Vue always ignores any <script> tags in the templates with error message:

    Templates should only be responsible for mapping the state to the UI. Avoid placing tags with side-effects in your templates, such as <script>, as they will not be parsed.

    1. There is no reason to put this into the template. It is just a regular JS code you can execute as part of the component lifecycle. Below is very simple component wrapper that integrates TinyMCE into Vue app.

    However I do not recommend doing this by yourself and instead use official Vue wrapper (docs) - use v3 for Vue 2. Official integration handles all the edge cases like component activation/deactivation (when used together with <keep-alive>) and proper cleanup when the component is destroyed which is required in order to avoid nasty memory leaks

    const ed = Vue.component("MyEditor", {
      props: ["id", "value"],
      template: `
        <div>
          <textarea :id="id" :value="value"></textarea>
        </div>
      `,
      mounted() {
        const me = this;
        window.tinymce.init({
          selector: "#" + this.id,
          plugins: "emoticons",
          toolbar: "emoticons",
          toolbar_location: "bottom",
          menubar: false,
          setup: function (editor) {
            editor.on("change input undo redo", function () {
              me.$emit('input', editor.getContent({format: 'text'}))
            });
          }
        });
      }
    });
    

    Demo

    Nuxt

    As TinyMCE is completely JS rendered, it does not make sense to execute it during server side rendering. In fact, above code will not work at all on server as there is no window variable. Use Nuxt's <client-only> component to force Nuxt to render editor only on the client...

    UPDATE: On the other side the mounted lifecycle hook is not called during SSR at all so maybe this will work just fine even without the <client-only>