Learn how to integrate tinymce 8 in rails 7+ using stimulus. step-by-step guide with self-hosted setup, clean configuration, and best seo practices for developers.
Introduction
Are you looking to integrate TinyMCE 8 into your Rails 7+ application with Stimulus? TinyMCE 8 brings modern, robust, and highly customizable rich-text editing, but using it in Rails can be tricky if you want a self-hosted setup.
In this tutorial, we will show you step-by-step how to:
-
Self-host TinyMCE 8 in Rails
-
Load TinyMCE via Stimulus controllers
-
Avoid deprecated warnings like
forced_root_block
-
Properly configure plugins, themes, and skins
By the end of this guide, you’ll have a fully functional, production-ready TinyMCE editor integrated seamlessly into your Rails application.
Step 1: Download TinyMCE 8
-
Visit the TinyMCE Self-Hosted Download
-
Download the latest TinyMCE 8 ZIP package.
-
Extract it into your Rails project under
public/vendor/tinymce
:mkdir -p public/vendor/tinymce
Recommended Folder Structure
⚡ Tip: Usepublic/vendor/tinymce/
├── tinymce.min.js
├── plugins/
│ ├── advlist/plugin.js
│ ├── autolink/plugin.js
│ └── ... other plugins
├── themes/
│ └── silver/theme.js
├── skins/
│ ├── ui/oxide/skin.min.css
│ └── content/default/content.min.css
├── models/
│ └── dom/model.js
├── icons/
│ └── default/icons.jscontent.min.css
instead ofcontent.css
to avoid 404 errors in Rails.
Step 2: Generate a Stimulus Controller
Generate a Stimulus controller for TinyMCE:
rails generate stimulus tinymce
This will create app/javascript/controllers/tinymce_controller.js
.
Step 3: Configure TinyMCE in Stimulus
Update your tinymce_controller.js
:
import { Controller } from "@hotwired/stimulus";
import "tinymce";
export default class extends Controller {
static targets = ["textarea"];
connect() {
this.initializeEditor();
}
disconnect() {
this.destroyEditor();
}
initializeEditor() {
if (typeof tinymce === "undefined") {
console.warn("TinyMCE is not loaded.");
return;
}
const textarea = this.textareaTarget;
if (!textarea || tinymce.get(textarea.id)) return;
tinymce.baseURL = "/vendor/tinymce";
tinymce.init({
target: textarea,
skin_url: "/vendor/tinymce/skins/ui/oxide",
content_css: "/vendor/tinymce/skins/content/default/content.min.css",
license_key: "gpl", // open-source license
body_class: "tinymce-content",
plugins: [
"advlist", "autolink", "lists", "link", "charmap", "preview", "anchor",
"insertdatetime", "fullscreen", "image", "code", "searchreplace",
"wordcount", "visualblocks", "visualchars", "directionality",
"nonbreaking", "media", "help"
],
toolbar: "undo redo | blocks | link | table | searchreplace | formatselect | bold italic backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | image | removeformat | help",
height: textarea.dataset.height || "600px",
valid_elements: "*[*]", // allow all HTML
setup: (editor) => {
editor.on("change", () => {
clearTimeout(this.saveTimeout);
this.saveTimeout = setTimeout(() => {
textarea.value = editor.getContent();
}, 300);
});
editor.on("init", () => {
editor.setContent(textarea.value);
});
},
});
}
destroyEditor() {
const editor = tinymce.get(this.textareaTarget?.id);
if (editor) editor.remove();
}
}
✅ TinyMCE 8 no longer requires
forced_root_block
, so removing it avoids console warnings.
Step 4: Add TinyMCE to Your Views
Use a textarea with the Stimulus controller attached:
<textarea data-controller="tinymce" data-tinymce-target="textarea" data-height="400px"></textarea>
Step 5: Test Your Editor
-
Start the Rails server:
-
Navigate to the page with your textarea. You should see a fully functional TinyMCE editor with all plugins and toolbar options working.
Step 6: Optional Customizations
-
Toolbar customization:
toolbar: "undo redo | bold italic | alignleft aligncenter alignright | bullist numlist"
- Dynamic height:
<textarea data-controller="tinymce" data-tinymce-target="textarea" data-height="500px"></textarea>
-
Add or remove plugins depending on your app’s needs.
Common Issues & Fixes
Issue | Fix |
---|---|
CSS 404 errors | Use content.min.css instead of content.css |
forced_root_block warning |
Remove the option entirely in TinyMCE 8 |
License warning | Add license_key: "gpl" in the init config |
Plugin 404 errors | Ensure all plugins are copied into public/vendor/tinymce/plugins |
FAQ
Q: Can I still use forced_root_block: false
?
A: TinyMCE 8 no longer requires it. Omitting it entirely is cleaner and prevents warnings.
Q: Should I host TinyMCE via importmap or public/vendor?
A: For Rails 7, self-hosting under public/vendor
is recommended for full control, offline support, and correct asset loading.
Q: Can I customize skins and themes?
A: Yes. You can change skin_url
and content_css
to use your own styles.
Conclusion
Following this tutorial, you now have a modern TinyMCE 8 editor in Rails 7 with Stimulus, fully self-hosted, with:
-
All plugins and skins working
-
Easy customization via Stimulus
This setup ensures fast loading, SEO-friendly content editing, and maintainability in production Rails apps.