Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save dhairyagabha/034f5baefb054b7b960438aaf3d88341 to your computer and use it in GitHub Desktop.
Save dhairyagabha/034f5baefb054b7b960438aaf3d88341 to your computer and use it in GitHub Desktop.
Rails & Trix: Add Underline, Superscript, and Subscript

Rails & Trix: Add Underline, Superscript, and Subscript

This guide will walk you through adding some extra features such as the ability to underline your text, or enhance your content by adding superscripts or subscripts for annotations or Math equations.

Prerequisites: Instruction guide assumes that you have created a Rails application and installed ActionText.

What will you learn:

Add action_text initializer file

# config/initializer/action_text.rb

Rails.application.config.after_initialize do
  ActionText::ContentHelper.allowed_tags << "u"
  ActionText::ContentHelper.allowed_tags << "sup"
  ActionText::ContentHelper.allowed_tags << "sub"
end

Add and compile Javascript for Trix Customization

import Trix from "trix"
Trix.config.textAttributes.sup = { tagName: "sup", inheritable: true };
Trix.config.textAttributes.sub = { tagName: "sub", inheritable: true };
Trix.config.textAttributes.underline = { tagName: "u", inheritable: false};

document.addEventListener("trix-initialize", function(event) {
  var element = event.target
  var editor = element.editor
  var toolbarElement = element.toolbarElement
  var groupElement = toolbarElement.querySelector(".trix-button-group.trix-button-group--text-tools")

  groupElement.insertAdjacentHTML("beforeend",'<button type="button" class="trix-button trix-button--icon trix-button--icon-underline" data-trix-attribute="underline"><sub>Underline</sub></button>')
  groupElement.insertAdjacentHTML("beforeend", '<button type="button" class="trix-button trix-button--icon trix-button--icon-sup" data-trix-attribute="sup"><sup>Superscript</sup></button>')
  groupElement.insertAdjacentHTML("beforeend",'<button type="button" class="trix-button trix-button--icon trix-button--icon-sub" data-trix-attribute="sub"><sub>Subscript</sub></button>')

  var selectedAttributes = new Set
  function updateSelectedAttributes() {
    selectedAttributes = new Set

    var selectedRange = editor.getSelectedRange()
    if (selectedRange[0] === selectedRange[1]) { selectedRange[1]++ }

    var selectedPieces = editor.getDocument().getDocumentAtRange(selectedRange).getPieces()
    selectedPieces.forEach(function(piece) {
      Object.keys(piece.getAttributes()).forEach(function(attribute) {
        selectedAttributes.add(attribute)
      })
    })
  }

  function enforceExclusiveAttributes() {
    if (editor.attributeIsActive("sup") && selectedAttributes.has("sub")) {
      editor.deactivateAttribute("sub")
      updateSelectedAttributes()
    } else if (editor.attributeIsActive("sub") && selectedAttributes.has("sup")) {
      editor.deactivateAttribute("sup")
      updateSelectedAttributes()
    }
  }

  updateSelectedAttributes()
  element.addEventListener("trix-selection-change", updateSelectedAttributes)
  element.addEventListener("trix-change", enforceExclusiveAttributes)

  if(element.dataset.content){
    editor.insertHTML(element.dataset.content)
  }
})

Add and compile CSS for Trix Customization

trix-toolbar .trix-button--icon-sup::before{
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="24" width="24"><path d="M500.065 270.691H383.611c3.092-18.342 24.015-34.022 47.984-50.038 34.415-22.995 76.138-50.642 76.138-103.222 0-50.301-38.48-85.431-93.577-85.431-37.629 0-72.116 19.458-90.794 50.314-3.321 5.486-1.706 12.623 3.631 16.18l24.42 16.276c5.32 3.546 12.556 2.364 16.309-2.812 10.243-14.13 24.825-24.68 42.168-24.68 26.189 0 37.912 17.288 37.912 34.421 0 21.219-22.471 36.854-48.49 54.956-35.769 24.886-80.283 55.857-80.283 114.931 0 5.562.558 11.025 1.433 17.915.762 5.997 5.861 10.499 11.906 10.499H500c6.627 0 12-5.373 12-12v-25.375c0-6.591-5.343-11.934-11.935-11.934zM245.92 432H276c6.627 0 12 5.373 12 12v24c0 6.627-5.373 12-12 12h-59.675a12 12 0 0 1-10.19-5.662l-54.204-87.153c-3.262-4.892-6.132-10.128-7.99-13.714-1.773 3.559-4.575 8.823-8.129 14.317l-53.058 86.488A12.005 12.005 0 0 1 72.524 480H12c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h31.728l65.48-100.449L48.755 240H12c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h66.764a12 12 0 0 1 10.234 5.734l47.525 77.624c2.986 4.976 5.742 10.45 7.54 14.194 1.856-3.636 4.718-8.991 7.984-14.217l48.63-77.701A12 12 0 0 1 210.849 192H276c6.627 0 12 5.373 12 12v24c0 6.627-5.373 12-12 12h-36.769l-60.974 90.984L245.92 432z" class=""></path></svg>');
  height: 18px;
  width: 18px;
  margin: auto auto;
}

trix-toolbar .trix-button--icon-sub::before{
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M500.065 430.691H383.611c3.092-18.342 24.015-34.022 47.984-50.038 34.415-22.995 76.138-50.642 76.138-103.222 0-50.301-38.48-85.431-93.577-85.431-37.629 0-72.116 19.458-90.794 50.314-3.321 5.486-1.706 12.623 3.631 16.18l24.42 16.276c5.32 3.546 12.556 2.364 16.309-2.812 10.243-14.13 24.825-24.68 42.168-24.68 26.189 0 37.912 17.288 37.912 34.421 0 21.219-22.471 36.854-48.49 54.956-35.769 24.886-80.283 55.857-80.283 114.931 0 5.562.558 11.025 1.433 17.915.762 5.997 5.861 10.499 11.906 10.499H500c6.627 0 12-5.373 12-12v-25.375c0-6.591-5.343-11.934-11.935-11.934zM245.92 272H276c6.627 0 12 5.373 12 12v24c0 6.627-5.373 12-12 12h-59.675a12 12 0 0 1-10.19-5.662l-54.204-87.153c-3.262-4.892-6.132-10.128-7.99-13.714-1.773 3.559-4.575 8.823-8.129 14.317l-53.058 86.488A12.005 12.005 0 0 1 72.524 320H12c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h31.728l65.48-100.449L48.755 80H12C5.373 80 0 74.627 0 68V44c0-6.627 5.373-12 12-12h66.764a12 12 0 0 1 10.234 5.734l47.525 77.624c2.986 4.976 5.742 10.45 7.54 14.194 1.856-3.636 4.718-8.991 7.984-14.217l48.63-77.701A12.002 12.002 0 0 1 210.85 32H276c6.627 0 12 5.373 12 12v24c0 6.627-5.373 12-12 12h-36.769l-60.974 90.984L245.92 272z" class=""></path></svg>');
  height: 18px;
  width: 18px;
  margin: auto auto;
}

trix-toolbar .trix-button--icon-underline::before{
  background-image: url('data:image/svg+xml;utf8,<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 1024 1024" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M824 804H200c-4.4 0-8 3.4-8 7.6v60.8c0 4.2 3.6 7.6 8 7.6h624c4.4 0 8-3.4 8-7.6v-60.8c0-4.2-3.6-7.6-8-7.6zm-312-76c69.4 0 134.6-27.1 183.8-76.2C745 602.7 772 537.4 772 468V156c0-6.6-5.4-12-12-12h-60c-6.6 0-12 5.4-12 12v312c0 97-79 176-176 176s-176-79-176-176V156c0-6.6-5.4-12-12-12h-60c-6.6 0-12 5.4-12 12v312c0 69.4 27.1 134.6 76.2 183.8C377.3 701 442.6 728 512 728z"></path></svg>');
  height: 18px;
  width: 18px;
  margin: auto auto;
}

trix-toolbar .trix-button-row{
  overflow: scroll;
}
@facedo
Copy link

facedo commented Aug 5, 2023

Thank you. I'll do it.

@facedo
Copy link

facedo commented Aug 5, 2023

I did it but broke bootstrap :(

@lucaszmoraes
Copy link

@facedo worked here on Rails 7; here is what I've done:

  1. create a new file to add the action_text initializer file at config/initializer/action_text.rb
  2. added the whole JS on application.js (step 2 Add and compile Javascript for Trix Customization)
  3. added the CSS on the actiontext.css file (step 3)

and that's it!

@facedo
Copy link

facedo commented Aug 28, 2023

Works fine! Thank you 1000 :-)

@tdak
Copy link

tdak commented Nov 14, 2023

Rails 7.1 Fix for the initializer

Rails.application.config.after_initialize do
  ActionText::ContentHelper.allowed_tags = Loofah::HTML5::SafeList::ACCEPTABLE_ELEMENTS
end

ACCEPTABLE_ELEMENTS contains u and sub and sup.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment