Skip to content →

Let’s create a Trix Editor plugin using Stimulus.js

I’ve been working on an app that uses Trix to edit a very complicated book text. Someone asked if I could add the ability to choose different sizes of text while they are editing the book. After digging around online, I came across this example from Javan, one of Trix’s creators: https://codepen.io/javan/pen/EPqzZo. This was exactly what I wanted, only with different actions.

After looking into Trix’s source code to figure out all the attributes the buttons needed, I added some H2 and H3 buttons to the title bar with this code:

<script>
  (function() {
	Trix.config.blockAttributes.heading2 = {
	  tagName: "h2",
	  terminal: true,
	  breakOnReturn: true,
	  group: false
	}
	Trix.config.blockAttributes.heading3 = {
	  tagName: "h3",
	  terminal: true,
	  breakOnReturn: true,
	  group: false
	}

	var h2ButtonHTML = '<button type="button" data-trix-attribute="heading2" title="Subheading">H2</button>'
	var h3ButtonHTML = '<button type="button" data-trix-attribute="heading3" title="Subheading">H3</button>'

	
  	var groupElement = Trix.config.toolbar.content.querySelector(".block_tools")

  	groupElement.insertAdjacentHTML("beforeend", h2ButtonHTML)
	groupElement.insertAdjacentHTML("beforeend", h3ButtonHTML)
  }).call(this);
</script>

<trix-editor input="book_text"></trix-editor>
<input id="book_text" value="" type="hidden" name="content">

The code worked really well, but I wasn’t too happy with how it looked, since this was all over the HTML of the page.

I mulled it over for a while, and realized that this could all go inside the connect() function of a Stimulus controller. I could even name the controller something descriptive like h2_plugin_controller.js, and my html would look clean and make sense, and I could wrap the code into different controllers, adding them to an editor when they made sense.

The above code was then refactored into two different controllers.

Here is trix_h2_plugin_controller.js:

import { Controller } from "stimulus"

export default class extends Controller {

  connect() {
	Trix.config.blockAttributes.heading2 = {
	  tagName: "h2",
	  terminal: true,
	  breakOnReturn: true,
	  group: false
	}
	
	var h2ButtonHTML = '<button type="button" data-trix-attribute="heading2" title="Subheading">H2</button>'
	var groupElement = Trix.config.toolbar.content.querySelector(".block_tools")
	groupElement.insertAdjacentHTML("beforeend", h2ButtonHTML)
  }
}

And here is trix_h3_plugin_controller.js:

import { Controller } from "stimulus"

export default class extends Controller {

  connect() {
	Trix.config.blockAttributes.heading3 = {
	  tagName: "h3",
	  terminal: true,
	  breakOnReturn: true,
	  group: false
	}
	
	var h3ButtonHTML = '<button type="button" data-trix-attribute="heading3" title="Subheading">H3</button>'
	var groupElement = Trix.config.toolbar.content.querySelector(".block_tools")
	groupElement.insertAdjacentHTML("beforeend", h3ButtonHTML)
  }
}

My html becomes much cleaner with just some Stimulus annotations:

<trix-editor input="book_text" data-controller="trix-h2-plugin trix-h3-plugin"></trix-editor>
<input id="book_text" value="" type="hidden" name="content">

I hope this helps give you some ideas for the flexibility of Stimulus’ controller model. You are able to drop little bits of functionality wherever you need them, even inside other Javascript libraries.

Comments or Questions? Find me on twitter @jpbeatty

Want To Learn More?

Try out some more of my Stimulus.js Tutorials.

Get the next tutorial when it comes out!

Please enter your email below, and you won’t miss the next Stimulus JS Tutorial


Published in Uncategorized

Comments are closed.