Skip to content

Conversation

@seanpdoyle
Copy link
Collaborator

@seanpdoyle seanpdoyle commented Sep 21, 2025

Prior to this change, Trix's rendering process was managed internally,
and was not open for extension or customization. While it's critical
that Trix manages its own content (through parsing HTML, scrubbing
attributes and sanitizing content, reifying attachments, etc.), the
"rendering" of that content amounts to the replacement of a collection
of DOM nodes.

Advanced use cases (like integration with "morph" style rendering) can
benefit from customizing the process of rendering Trix's content.

This commit introduces a trix-before-render event to with a render
property to configure an individual <trix-editor> element's rendering
process. By default, the event's render property maintains the
existing "replace" behavior. When overridden, the function expects two
arguments: a <trix-editor> element along with with a
DocumentFragment instance.

document.addEventListener("trix-before-render", (event) => {
  const defaultRender = event.render

  event.render = function(editorElement, documentFragment) {
    // modify the documentFragment…
    customize(documentFragment)

    // render it with the default rendering function
    defaultRender(editorElement, documentFragment)
  }
})

@seanpdoyle seanpdoyle mentioned this pull request Sep 21, 2025
3 tasks
@seanpdoyle seanpdoyle changed the title TrixEditorElement.render property Dispatch trix-before-render event Sep 21, 2025
Prior to this change, Trix's rendering process was managed internally,
and was not open for extension or customization. While it's critical
that Trix manages its own content (through parsing HTML, scrubbing
attributes and sanitizing content, reifying attachments, etc.), the
"rendering" of that content amounts to the replacement of a collection
of DOM nodes.

Advanced use cases (like integration with "morph" style rendering) can
benefit from customizing the process of rendering Trix's content.

This commit introduces a `trix-before-render` event to with a `render`
property to configure an individual `<trix-editor>` element's rendering
process. By default, the event's `render` property maintains the
existing "replace" behavior. When overridden, the function expects two
arguments: a `<trix-editor>` element along with with a
[DocumentFragment][] instance.

```js
document.addEventListener("trix-before-render", (event) => {
  const defaultRender = event.render

  event.render = function(editorElement, documentFragment) {
    // modify the documentFragment…
    customize(documentFragment)

    // render it with the default rendering function
    defaultRender(editorElement, documentFragment)
  }
})
```

[DocumentFragment]: https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment
Comment on lines +6 to +10
function renderWithMorph(event) {
event.render = (editorElement, documentFragment) => {
Idiomorph.morph(editorElement, documentFragment, { morphStyle: "innerHTML" })
}
}
Copy link
Collaborator Author

@seanpdoyle seanpdoyle Sep 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consumers (like turbo-rails) are free to extend rendering as they see fit. If something like hotwired/turbo#1319 were to be merged, turbo-rails could come with an event handler like:

import { morphChildren } from "@hotwired/turbo"

const renderWithMorphing = (event) => event.render = morphChildren

addEventHandler("turbo:before-morph-element", ({ target: editor }) => {
  if (editor.matches("trix-editor")) {
    editor.addEventListener("trix-before-render", renderWithMorphing)
    editor.addEventListener("turbo:morph-element", () => {
      editor.removeEventListener("trix-before-render", renderWithMorphing)
    }, { once: true })
  }
})

That way, the typical Turbo Morph events would fire when morphing Trix content.

@jorgemanrubia jorgemanrubia merged commit fc15ab2 into basecamp:main Sep 21, 2025
2 checks passed
@seanpdoyle seanpdoyle deleted the editor-render branch September 21, 2025 22:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants