I've recently upgraded an app to Rails 7 and I'm using importmap-rails for all of my javascript. Previously the app used Webpacker and I have all of the javascript working via importmaps except customizing the Trix toolbar to add an Underline button to the Trix Toolbar. To do this with Webpacker, I had used this JS file to customize the Trix toolbar:
trix_extensions.js
:
var Trix = require("trix")
Trix.config.textAttributes.underline = {
tagName: 'u'
}
const {lang} = Trix.config;
Trix.config.toolbar = {
getDefaultHTML() { return `
<div class="trix-button-row">
<span class="trix-button-group trix-button-group--text-tools" data-trix-button-group="text-tools">
<button type="button" class="trix-button trix-button--icon trix-button--icon-bold" data-trix-attribute="bold" data-trix-key="b" title="${lang.bold}" tabindex="-1">#{lang.bold}</button>
<button type="button" class="trix-button trix-button--icon trix-button--icon-italic" data-trix-attribute="italic" data-trix-key="i" title="${lang.italic}" tabindex="-1">${lang.italic}</button>
<button type="button" class="trix-button trix-button--icon trix-button--icon-strike" data-trix-attribute="strike" title="${lang.strike}" tabindex="-1">${lang.strike}</button>
<button type="button" class="trix-button trix-button--icon trix-button--icon-underline" data-trix-attribute="underline" data-trix-key="u" title="underline" tabindex="-1">${lang.underline}</button>
<button type="button" class="trix-button trix-button--icon trix-button--icon-link" data-trix-attribute="href" data-trix-action="link" data-trix-key="k" title="${lang.link}" tabindex="-1">${lang.link}</button>
</span>
<span class="trix-button-group trix-button-group--block-tools" data-trix-button-group="block-tools">
<button type="button" class="trix-button trix-button--icon trix-button--icon-heading-1" data-trix-attribute="heading1" title="${lang.heading1}" tabindex="-1">${lang.heading1}</button>
<button type="button" class="trix-button trix-button--icon trix-button--icon-quote" data-trix-attribute="quote" title="${lang.quote}" tabindex="-1">${lang.quote}</button>
<button type="button" class="trix-button trix-button--icon trix-button--icon-bullet-list" data-trix-attribute="bullet" title="${lang.bullets}" tabindex="-1">${lang.bullets}</button>
<button type="button" class="trix-button trix-button--icon trix-button--icon-number-list" data-trix-attribute="number" title="${lang.numbers}" tabindex="-1">${lang.numbers}</button>
<button type="button" class="trix-button trix-button--icon trix-button--icon-decrease-nesting-level" data-trix-action="decreaseNestingLevel" title="${lang.outdent}" tabindex="-1">${lang.outdent}</button>
<button type="button" class="trix-button trix-button--icon trix-button--icon-increase-nesting-level" data-trix-action="increaseNestingLevel" title="${lang.indent}" tabindex="-1">${lang.indent}</button>
</span>
<span class="trix-button-group trix-button-group--file-tools" data-trix-button-group="file-tools">
<button type="button" class="trix-button trix-button--icon trix-button--icon-attach" data-trix-action="attachFiles" title="${lang.attachFiles}" tabindex="-1">${lang.attachFiles}</button>
</span>
<span class="trix-button-group-spacer"></span>
<span class="trix-button-group trix-button-group--history-tools" data-trix-button-group="history-tools">
<button type="button" class="trix-button trix-button--icon trix-button--icon-undo" data-trix-action="undo" data-trix-key="z" title="${lang.undo}" tabindex="-1">${lang.undo}</button>
<button type="button" class="trix-button trix-button--icon trix-button--icon-redo" data-trix-action="redo" data-trix-key="shift+z" title="${lang.redo}" tabindex="-1">${lang.redo}</button>
</span>
</div>
<div class="trix-dialogs" data-trix-dialogs>
<div class="trix-dialog trix-dialog--link" data-trix-dialog="href" data-trix-dialog-attribute="href">
<div class="trix-dialog__link-fields">
<input type="url" name="href" class="trix-input trix-input--dialog" placeholder="${lang.urlPlaceholder}" aria-label="${lang.url}" required data-trix-input>
<div class="trix-button-group">
<input type="button" class="trix-button trix-button--dialog" value="${lang.link}" data-trix-method="setAttribute">
<input type="button" class="trix-button trix-button--dialog" value="${lang.unlink}" data-trix-method="removeAttribute">
</div>
</div>
</div>
</div>
`; }
};
But I can't get this JS to work via importmaps. I tried switching the var Trix = require("trix")
to import Trix from "trix";
as well as just dropping all of that directly into a tag in the HTML header just to see if I could get it working at all, but no luck.
How can I customize the Trix toolbar in Rails 7 with importmap-rails
? Do I also need to add import "@rails/actiontext"
?
FYI - I'm loading all other vanilla, non-stimulus JS in config/importmap.rb
and then importing it in javascript/application.js
with lines like this import "custom/trix_extensions.js"
etc.
My trix_extensions.js
appears to be loading correctly via my import map because I'm getting a ReferenceError: Can't find variable: require
in the console. So it tells me the issue is with how I'm importing Trix into my trix_extensions.js
file. Also, the default Trix toolbar is loading properly and works as expected. I'm just not seeing my customizations.
So the problem appears to be with how to extend Trix when importing it with importmaps.
Here's my full config/importmap.rb
file:
pin "@rails/activestorage", to: "activestorage.esm.js"
pin "application", preload: true
pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true
pin "@hotwired/stimulus", to: ":@hotwired/[email protected]/dist/stimulus.js"
pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true
pin_all_from "app/javascript/controllers", under: "controllers"
pin "alpinejs", to: "/[email protected]/dist/module.esm.js", preload: true
pin "@rails/ujs", to: ":@rails/[email protected]/lib/assets/piled/rails-ujs.js"
pin "@rails/request.js", to: ":@rails/[email protected]/src/index.js", preload: true
pin "trix", to: ":[email protected]/dist/trix.js"
pin "@rails/actiontext", to: "actiontext.js"
pin "sortablejs", to: ":[email protected]/modular/sortable.esm.js"
pin "tailwindcss-stimulus-ponents", to: ":[email protected]/dist/tailwindcss-stimulus-ponents.modern.js"
pin_all_from "app/javascript/custom", under: "custom"
And my javascript/application.js
file:
// Configure your import map in config/importmap.rb. Read more:
import "@hotwired/turbo-rails"
import "@rails/activestorage"
import "controllers"
import "trix"
import "@rails/actiontext"
import "custom/direct_uploads"
import "custom/stripe_payments"
import "custom/table_sort"
import "custom/trix_extensions"
I've recently upgraded an app to Rails 7 and I'm using importmap-rails for all of my javascript. Previously the app used Webpacker and I have all of the javascript working via importmaps except customizing the Trix toolbar to add an Underline button to the Trix Toolbar. To do this with Webpacker, I had used this JS file to customize the Trix toolbar:
trix_extensions.js
:
var Trix = require("trix")
Trix.config.textAttributes.underline = {
tagName: 'u'
}
const {lang} = Trix.config;
Trix.config.toolbar = {
getDefaultHTML() { return `
<div class="trix-button-row">
<span class="trix-button-group trix-button-group--text-tools" data-trix-button-group="text-tools">
<button type="button" class="trix-button trix-button--icon trix-button--icon-bold" data-trix-attribute="bold" data-trix-key="b" title="${lang.bold}" tabindex="-1">#{lang.bold}</button>
<button type="button" class="trix-button trix-button--icon trix-button--icon-italic" data-trix-attribute="italic" data-trix-key="i" title="${lang.italic}" tabindex="-1">${lang.italic}</button>
<button type="button" class="trix-button trix-button--icon trix-button--icon-strike" data-trix-attribute="strike" title="${lang.strike}" tabindex="-1">${lang.strike}</button>
<button type="button" class="trix-button trix-button--icon trix-button--icon-underline" data-trix-attribute="underline" data-trix-key="u" title="underline" tabindex="-1">${lang.underline}</button>
<button type="button" class="trix-button trix-button--icon trix-button--icon-link" data-trix-attribute="href" data-trix-action="link" data-trix-key="k" title="${lang.link}" tabindex="-1">${lang.link}</button>
</span>
<span class="trix-button-group trix-button-group--block-tools" data-trix-button-group="block-tools">
<button type="button" class="trix-button trix-button--icon trix-button--icon-heading-1" data-trix-attribute="heading1" title="${lang.heading1}" tabindex="-1">${lang.heading1}</button>
<button type="button" class="trix-button trix-button--icon trix-button--icon-quote" data-trix-attribute="quote" title="${lang.quote}" tabindex="-1">${lang.quote}</button>
<button type="button" class="trix-button trix-button--icon trix-button--icon-bullet-list" data-trix-attribute="bullet" title="${lang.bullets}" tabindex="-1">${lang.bullets}</button>
<button type="button" class="trix-button trix-button--icon trix-button--icon-number-list" data-trix-attribute="number" title="${lang.numbers}" tabindex="-1">${lang.numbers}</button>
<button type="button" class="trix-button trix-button--icon trix-button--icon-decrease-nesting-level" data-trix-action="decreaseNestingLevel" title="${lang.outdent}" tabindex="-1">${lang.outdent}</button>
<button type="button" class="trix-button trix-button--icon trix-button--icon-increase-nesting-level" data-trix-action="increaseNestingLevel" title="${lang.indent}" tabindex="-1">${lang.indent}</button>
</span>
<span class="trix-button-group trix-button-group--file-tools" data-trix-button-group="file-tools">
<button type="button" class="trix-button trix-button--icon trix-button--icon-attach" data-trix-action="attachFiles" title="${lang.attachFiles}" tabindex="-1">${lang.attachFiles}</button>
</span>
<span class="trix-button-group-spacer"></span>
<span class="trix-button-group trix-button-group--history-tools" data-trix-button-group="history-tools">
<button type="button" class="trix-button trix-button--icon trix-button--icon-undo" data-trix-action="undo" data-trix-key="z" title="${lang.undo}" tabindex="-1">${lang.undo}</button>
<button type="button" class="trix-button trix-button--icon trix-button--icon-redo" data-trix-action="redo" data-trix-key="shift+z" title="${lang.redo}" tabindex="-1">${lang.redo}</button>
</span>
</div>
<div class="trix-dialogs" data-trix-dialogs>
<div class="trix-dialog trix-dialog--link" data-trix-dialog="href" data-trix-dialog-attribute="href">
<div class="trix-dialog__link-fields">
<input type="url" name="href" class="trix-input trix-input--dialog" placeholder="${lang.urlPlaceholder}" aria-label="${lang.url}" required data-trix-input>
<div class="trix-button-group">
<input type="button" class="trix-button trix-button--dialog" value="${lang.link}" data-trix-method="setAttribute">
<input type="button" class="trix-button trix-button--dialog" value="${lang.unlink}" data-trix-method="removeAttribute">
</div>
</div>
</div>
</div>
`; }
};
But I can't get this JS to work via importmaps. I tried switching the var Trix = require("trix")
to import Trix from "trix";
as well as just dropping all of that directly into a tag in the HTML header just to see if I could get it working at all, but no luck.
How can I customize the Trix toolbar in Rails 7 with importmap-rails
? Do I also need to add import "@rails/actiontext"
?
FYI - I'm loading all other vanilla, non-stimulus JS in config/importmap.rb
and then importing it in javascript/application.js
with lines like this import "custom/trix_extensions.js"
etc.
My trix_extensions.js
appears to be loading correctly via my import map because I'm getting a ReferenceError: Can't find variable: require
in the console. So it tells me the issue is with how I'm importing Trix into my trix_extensions.js
file. Also, the default Trix toolbar is loading properly and works as expected. I'm just not seeing my customizations.
So the problem appears to be with how to extend Trix when importing it with importmaps.
Here's my full config/importmap.rb
file:
pin "@rails/activestorage", to: "activestorage.esm.js"
pin "application", preload: true
pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true
pin "@hotwired/stimulus", to: "https://ga.jspm.io/npm:@hotwired/[email protected]/dist/stimulus.js"
pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true
pin_all_from "app/javascript/controllers", under: "controllers"
pin "alpinejs", to: "https://unpkg./[email protected]/dist/module.esm.js", preload: true
pin "@rails/ujs", to: "https://ga.jspm.io/npm:@rails/[email protected]/lib/assets/piled/rails-ujs.js"
pin "@rails/request.js", to: "https://ga.jspm.io/npm:@rails/[email protected]/src/index.js", preload: true
pin "trix", to: "https://ga.jspm.io/npm:[email protected]/dist/trix.js"
pin "@rails/actiontext", to: "actiontext.js"
pin "sortablejs", to: "https://ga.jspm.io/npm:[email protected]/modular/sortable.esm.js"
pin "tailwindcss-stimulus-ponents", to: "https://ga.jspm.io/npm:[email protected]/dist/tailwindcss-stimulus-ponents.modern.js"
pin_all_from "app/javascript/custom", under: "custom"
And my javascript/application.js
file:
// Configure your import map in config/importmap.rb. Read more: https://github./rails/importmap-rails
import "@hotwired/turbo-rails"
import "@rails/activestorage"
import "controllers"
import "trix"
import "@rails/actiontext"
import "custom/direct_uploads"
import "custom/stripe_payments"
import "custom/table_sort"
import "custom/trix_extensions"
Share
Improve this question
asked Apr 1, 2022 at 20:11
Lee McAlillyLee McAlilly
9,32412 gold badges64 silver badges97 bronze badges
1 Answer
Reset to default 6FYI - I got this working with the following in my javascript/custom/trix_extensions.js
file:
// Modified from this: https://github./ParamagicDev/exploring-trix/blob/part01-changing-the-default-toolbar/main.js
import Trix from 'trix';
window.Trix = Trix; // Don't need to bind to the window, but useful for debugging.
Trix.config.toolbar.getDefaultHTML = toolbarDefaultHTML;
// trix-before-initialize runs too early.
// We only need to do this once. Everything after initialize will get the
// defaultHTML() call automatically.
document.addEventListener('trix-initialize', updateToolbars, { once: true });
function updateToolbars(event) {
const toolbars = document.querySelectorAll('trix-toolbar');
const html = Trix.config.toolbar.getDefaultHTML();
toolbars.forEach((toolbar) => (toolbar.innerHTML = html));
}
Trix.config.textAttributes.underline = {
tagName: 'u'
}
const {lang} = Trix.config;
/**
* This is the default Trix toolbar. Feel free to change / manipulate it how you would like.
* see https://github./basecamp/trix/blob/main/src/trix/config/toolbar.coffee
*/
function toolbarDefaultHTML() {
const {lang} = Trix.config;
return `
<div class="trix-button-row">
<span class="trix-button-group trix-button-group--text-tools" data-trix-button-group="text-tools">
<button type="button" class="trix-button trix-button--icon trix-button--icon-bold" data-trix-attribute="bold" data-trix-key="b" title="${lang.bold}" tabindex="-1">#{lang.bold}</button>
<button type="button" class="trix-button trix-button--icon trix-button--icon-italic" data-trix-attribute="italic" data-trix-key="i" title="${lang.italic}" tabindex="-1">${lang.italic}</button>
<button type="button" class="trix-button trix-button--icon trix-button--icon-strike" data-trix-attribute="strike" title="${lang.strike}" tabindex="-1">${lang.strike}</button>
<button type="button" class="trix-button trix-button--icon trix-button--icon-underline" data-trix-attribute="underline" data-trix-key="u" title="underline" tabindex="-1">${lang.underline}</button>
<button type="button" class="trix-button trix-button--icon trix-button--icon-link" data-trix-attribute="href" data-trix-action="link" data-trix-key="k" title="${lang.link}" tabindex="-1">${lang.link}</button>
</span>
<span class="trix-button-group trix-button-group--block-tools" data-trix-button-group="block-tools">
<button type="button" class="trix-button trix-button--icon trix-button--icon-heading-1" data-trix-attribute="heading1" title="${lang.heading1}" tabindex="-1">${lang.heading1}</button>
<button type="button" class="trix-button trix-button--icon trix-button--icon-quote" data-trix-attribute="quote" title="${lang.quote}" tabindex="-1">${lang.quote}</button>
<button type="button" class="trix-button trix-button--icon trix-button--icon-bullet-list" data-trix-attribute="bullet" title="${lang.bullets}" tabindex="-1">${lang.bullets}</button>
<button type="button" class="trix-button trix-button--icon trix-button--icon-number-list" data-trix-attribute="number" title="${lang.numbers}" tabindex="-1">${lang.numbers}</button>
<button type="button" class="trix-button trix-button--icon trix-button--icon-decrease-nesting-level" data-trix-action="decreaseNestingLevel" title="${lang.outdent}" tabindex="-1">${lang.outdent}</button>
<button type="button" class="trix-button trix-button--icon trix-button--icon-increase-nesting-level" data-trix-action="increaseNestingLevel" title="${lang.indent}" tabindex="-1">${lang.indent}</button>
</span>
<span class="trix-button-group trix-button-group--file-tools" data-trix-button-group="file-tools">
<button type="button" class="trix-button trix-button--icon trix-button--icon-attach" data-trix-action="attachFiles" title="${lang.attachFiles}" tabindex="-1">${lang.attachFiles}</button>
</span>
<span class="trix-button-group-spacer"></span>
<span class="trix-button-group trix-button-group--history-tools" data-trix-button-group="history-tools">
<button type="button" class="trix-button trix-button--icon trix-button--icon-undo" data-trix-action="undo" data-trix-key="z" title="${lang.undo}" tabindex="-1">${lang.undo}</button>
<button type="button" class="trix-button trix-button--icon trix-button--icon-redo" data-trix-action="redo" data-trix-key="shift+z" title="${lang.redo}" tabindex="-1">${lang.redo}</button>
</span>
</div>
<div class="trix-dialogs" data-trix-dialogs>
<div class="trix-dialog trix-dialog--link" data-trix-dialog="href" data-trix-dialog-attribute="href">
<div class="trix-dialog__link-fields">
<input type="url" name="href" class="trix-input trix-input--dialog" placeholder="${lang.urlPlaceholder}" aria-label="${lang.url}" required data-trix-input>
<div class="trix-button-group">
<input type="button" class="trix-button trix-button--dialog" value="${lang.link}" data-trix-method="setAttribute">
<input type="button" class="trix-button trix-button--dialog" value="${lang.unlink}" data-trix-method="removeAttribute">
</div>
</div>
</div>
</div>
`;
}
I think the key line I was missing was document.addEventListener('trix-initialize', updateToolbars, { once: true });
Thanks to https://github./ParamagicDev/ for sharing this here:
https://github./ParamagicDev/exploring-trix/blob/part01-changing-the-default-toolbar/main.js