Skip to content

Make Lexxy the default Action Text editor for new applications - #40

Open
jorgemanrubia wants to merge 5 commits into
mainfrom
action-text-lexxy-default
Open

jorgemanrubia wants to merge 5 commits into
mainfrom
action-text-lexxy-default

Conversation

@jorgemanrubia

@jorgemanrubia jorgemanrubia commented Sep 11, 2026 •

Copy link
Copy Markdown
Member

Motivation / Background

New Rails applications still start with Trix as their rich text editor. Lexxy is a newer editor for Action Text, built on Meta's Lexical, with real <p> paragraphs, Markdown shortcuts, code highlighting and attachment previews. It already plugs into Action Text through the editor adapter from Extract ActionText::Editor base class and ActionText::TrixEditor adapter, but only for applications that know to install it.

This makes Lexxy the editor new applications start with, and the only editor Action Text installs by default. Applications that upgrade must not change under their feet, so the switch goes through the versioned defaults mechanism, and existing Trix applications keep a clear path to keep Trix.

Detail

  • Defaults. config.action_text.editor still defaults to :trix, and becomes :lexxy in config.load_defaults "8.2". There is a commented entry in new_framework_defaults_8_2.rb, a versioned table in the Configuring guide, and a release notes entry. The steps and the application tests for new and upgraded apps mirror Undeprecate config.active_job.enqueue_after_transaction_commit and flip it to true by default.

  • Adapter. Action Text ships a Lexxy editor adapter next to the Trix one and registers both. Lexxy already emits Action Text's canonical HTML, so the adapter only renders <lexxy-editor> with the content in its value attribute.

  • Dependencies. Action Text now depends on lexxy and requires it, the way it used to depend on and require action_text-trix. It no longer depends on action_text-trix. Three Lexxy changes make that work:

    Until a Lexxy release includes all three, the Gemfile takes lexxy from rails-action-text-default, a basecamp/lexxy branch that combines them.

  • Trix is optional. This mirrors Rails 7.0's "Sprockets is now an optional dependency":

    • Applications that use Trix add gem "action_text-trix", including those that load Trix's JavaScript from npm or a vendored copy. The gem is small and only depends on railties, so I chose a single rule over an adapter option to bypass the check.
    • Rendering a Trix editor without the gem raises an error that says to add it, or links to switching to Lexxy.
    • The check runs at render, not at boot. Applications that load rails/all eager load Action Text even when they don't use rich text, and most upgraded applications keep :trix.
  • Installer. bin/rails action_text:install installs the editor config.action_text.editor names, or the one passed with --editor. It refuses an editor it can't set up.

    • For Trix, it adds gem "action_text-trix". For Lexxy, there's no gem to add.
    • When --editor differs from the configured editor, it writes config.action_text.editor into config/application.rb after config.load_defaults, replacing any plain assignment, so the choice takes effect.
    • It warns about other assignments in config/application.rb, initializers or environment files that would take precedence.
    • --editor came in with the adapter PR and hasn't shipped in a release.
  • Sanitizer. Rendered content keeps the markup Lexxy produces: tables, audio, video, source, embed, s, controls, poster, data-language, start, style and value. style values still go through Loofah's CSS scrubbing, which now allows var().

  • System test helper. fill_in_rich_textarea works with Lexxy, whose role="textbox" element sits inside <lexxy-editor>, and matches Trix exactly as before.

  • Tests.

    • The Action Text dummy app stays on Trix, and loads the action_text-trix gem from Rails' Gemfile.
    • New Lexxy system tests cover every locator, plus saving and editing.
    • Railties tests cover the editor defaults, the installer, and the new Lexxy::Engine position in the railtie order.
  • Docs. The Action Text overview, Configuring, Upgrading and Getting Started guides, the 8.2 release notes, the helper docs, the Action Text README and CHANGELOG are updated.

Existing Trix applications

  • Add the gem. Add gem "action_text-trix" to keep using Trix.

  • The editor setting. While config.load_defaults stays below 8.2, the editor doesn't change. To move to 8.2 defaults and keep Trix, set config.action_text.editor = :trix.

  • Apps already on Lexxy through the lexxy gem. Set config.action_text.editor = :lexxy, or move to 8.2 defaults. Otherwise they fall back to Trix, and the missing-gem error says so.

  • Switching to Lexxy. There's no gem to add. Swap the JavaScript imports, uncomment the entry in new_framework_defaults_8_2.rb, and change trix-content to lexxy-content in the content layout. The Upgrading guide covers these steps.

  • Stored rich text. It needs no migration. Rendering doesn't involve the editor, and Lexxy loads Trix's markup.

  • Changes for every application, whichever editor it uses.

    • The wider sanitizer allowlist.
    • Because Action Text now loads Lexxy, an attachment pointing at a video URL without a record renders as a remote video, and the JSON for a previewable blob includes previewable and a preview url when URL options are available.

    Applications that set ActionText::ContentHelper.allowed_tags or allowed_attributes keep their own lists.

Relationship to the editor adapter PR

This builds on Sean Doyle's Extract ActionText::Editor base class and ActionText::TrixEditor adapter, merged into main. It uses that PR's editor registry, adapter base class and config.action_text.editor without reimplementing any of it.

Prerequisites and open questions

  • A Lexxy release must include Depend on railties instead of rails lexxy#1260, STI's are not compatible with Rails 3.1 RC? rails/rails#1261 and Create the dummy app if there's no test_unit but there's a dummy_path rails/rails#1262 before this can go upstream. Then actiontext.gemspec should require that release, and the Gemfile's git source goes away. Until then, applications that use this branch have to pin rails-action-text-default too.
    • That's also why the fork's rails-new-docker and "Devcontainer smoke test" checks fail.
    • The app generated by rails new --dev resolves lexxy ~> 0.9.31 from RubyGems. That release still depends on rails, so Bundler refuses the cycle.
    • The Rails repository itself resolves, with and without its lockfile.
  • Explicit :trix on Rails without Lexxy. Lexxy can't tell an explicit config.action_text.editor = :trix from Action Text's default on Rails versions that don't include Lexxy, because Rails doesn't record who set it. There, config.lexxy.override_action_text_defaults = false is the explicit way to keep Trix while the gem is installed.
  • var() is process-wide. It's added to Loofah's CSS function allowlist, which is shared by the whole process, so it also applies to Action View's sanitize.
  • Fallback layout. The engine's fallback content layout still uses trix-content. The installer writes the application's copy with the configured editor's class.

Additional information

Tests run locally against rails-action-text-default:

Suite Runs Result
Action Text unit (rake test) 338 0 failures, 1 error
Action Text system (rake test:system, RACK_ENV=test set) 21 0 failures, 0 errors
railties/test/generators/action_text_install_generator_test.rb 32 0 failures
railties/test/application/configuration_test.rb, Action Text and enqueue_after_transaction_commit tests 13 0 failures
railties/test/railties/engine_test.rb, railtie order 1 0 failures
  • The unit error is JavascriptPackageTest, which needs rollup from node_modules, and it fails the same way on main.
  • Without RACK_ENV set, the system run's leak checker reports RACK_ENV being added when the test server boots. That happens on untouched main too.
  • Separate test fix. The commit "Reset Chrome network conditions without reading them back" fixes an existing system test helper, which left Chrome offline under the json 3.x gem.

Checklist

  • This Pull Request is related to one change. Unrelated changes should be opened in separate PRs.
  • Commit message has a detailed description of what changed and why. If this PR fixes a related issue include it in the commit message. Ex: [Fix #issue-number]
  • Tests are added or updated if you fix a bug or add a feature.
  • CHANGELOG files are updated for the changed libraries if there is a behavior change or additional feature. Minor bug fixes and documentation changes should not be included.

New applications, and applications that set `config.load_defaults "8.2"`,
render `rich_textarea` with Lexxy instead of Trix. Upgraded applications
keep Trix until they opt in.

The change builds on the editor adapter from rails#51238:

* `config.action_text.editor` still defaults to `:trix`, and becomes
  `:lexxy` in `load_defaults "8.2"`, with a commented entry in
  `new_framework_defaults_8_2.rb`.
* Action Text registers a Lexxy editor adapter next to the Trix one, so
  applications on the new defaults boot before the `lexxy` gem is added.
* `bin/rails action_text:install` installs the configured editor, or the
  one passed with `--editor`. For Lexxy, it adds the `lexxy` gem, its
  JavaScript and stylesheet, and the `lexxy-content` layout class.
* The Action Text dummy application pins Trix, which its forms and system
  tests exercise.

Stored rich text needs no migration: Lexxy loads content saved by Trix.
Copilot AI balanced review requested due to automatic review settings September 11, 2026 08:58

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Changes recommended

The installer silently maps unsupported configured editors to Trix, and its config-driven selection lacks direct coverage.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Makes Lexxy the default Action Text editor for Rails 8.2 applications while preserving Trix for upgraded applications.

Changes:

  • Adds and registers a Lexxy editor adapter.
  • Updates installation to configure Lexxy or Trix assets and dependencies.
  • Adds versioned defaults, tests, and documentation.

[!TIP]
If you aren't ready for review, convert to a draft PR.
Click "Convert to draft" or run gh pr ready --undo.
Click "Ready for review" or run gh pr ready to reengage.

File summaries
File Description
railties/test/generators/action_text_install_generator_test.rb Tests editor-specific installation.
railties/test/application/configuration_test.rb Tests versioned editor defaults.
railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_8_2.rb.tt Documents the 8.2 opt-in.
railties/lib/rails/application/configuration.rb Sets Lexxy for 8.2 defaults.
guides/source/upgrading_ruby_on_rails.md Documents migration between editors.
guides/source/getting_started.md Updates generated import-map pins.
guides/source/configuring.md Documents editor configuration.
guides/source/action_text_overview.md Updates Action Text installation and usage guidance.
guides/source/8_2_release_notes.md Announces the new default.
actiontext/test/unit/editor/lexxy_editor_test.rb Tests the Lexxy adapter.
actiontext/test/unit/editor/configurator_test.rb Tests Lexxy adapter construction.
actiontext/test/dummy/config/application.rb Keeps the test application on Trix.
actiontext/README.md Describes both supported editors.
actiontext/lib/generators/action_text/install/templates/trix/actiontext.css Provides the Trix stylesheet template.
actiontext/lib/generators/action_text/install/templates/lexxy/actiontext.css Imports Lexxy styles.
actiontext/lib/generators/action_text/install/templates/layouts/action_text/contents/_content.html.erb.tt Generates editor-specific content classes.
actiontext/lib/generators/action_text/install/install_generator.rb Selects and installs editor dependencies.
actiontext/lib/action_text/engine.rb Registers Lexxy and Trix.
actiontext/lib/action_text/editor/lexxy_editor.rb Implements Lexxy tag rendering.
actiontext/lib/action_text/attribute.rb Generalizes editor documentation.
actiontext/CHANGELOG.md Records the behavior change.
actiontext/app/models/action_text/rich_text.rb Generalizes model documentation.
actiontext/app/helpers/action_text/tag_helper.rb Documents editor-specific markup.
Review details
  • Files reviewed: 22/23 changed files
  • Comments generated: 3
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +76 to +77
def editor
@editor ||= options[:editor] || (lexxy_configured? ? "lexxy" : "trix")

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

🤖 Fixed in a0b15e6. The installer now refuses an editor it can't set up, with a message pointing at --editor=lexxy or --editor=trix, instead of falling back to Trix. A generator test covers it.

Comment on lines +126 to +127
# Lexxy's JavaScript and stylesheets are provided by the `lexxy` gem, so add it
# and import it in your JavaScript entrypoint before enabling this setting.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

🤖 Fixed in a0b15e6. The comment now says to set up Lexxy's JavaScript for import maps or a JavaScript bundler, and links Lexxy's installation instructions.

Comment on lines +134 to +135
test "adds the lexxy gem when installing Lexxy" do
run_generator_instance ["--editor=lexxy"]

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

🤖 Fixed in a0b15e6. New generator tests install the editor named by config.action_text.editor without --editor, and check that --editor=trix takes precedence over a configured :lexxy.

Action Text now depends on the lexxy gem, as it depends on
action_text-trix. Until a Lexxy release depends on railties instead of
rails, which would otherwise make the dependency circular, the Gemfile
takes lexxy from basecamp/lexxy. Action Text doesn't require the gem:
its engine sets config.action_text.editor to :lexxy when it loads, which
would switch existing Trix applications. The installer keeps adding it
to the Gemfile of applications that use Lexxy.

Action Text's sanitizer keeps the elements and attributes Lexxy
produces: tables, audio and video, strikethrough, code languages, and
style attributes reduced to safe CSS, now including var().

fill_in_rich_textarea finds editors like Lexxy, whose editable content
sits inside the editor element, by that element's attributes, and fills
them in through its value. The dummy application serves Lexxy's
JavaScript, and new system tests cover filling in, saving, and editing
rich text with Lexxy. TrixEditorTest's with_editor now switches to the
editor it names.

The installer refuses an editor it can't set up, instead of falling back
to Trix.
while_offline restored the previous network conditions with Object#with,
which reads them back from Chrome with string keys. Selenium then adds
its defaults as symbol keys, and json refuses to serialize the duplicate
keys. The error left Chrome offline, so the system tests that ran after
it failed with net::ERR_INTERNET_DISCONNECTED.
New applications get Lexxy only. Action Text no longer depends on
action_text-trix, and it requires lexxy the way it used to require
action_text/trix. On a Rails version that registers Lexxy, Lexxy leaves
config.action_text.editor, the sanitizer lists, and blob JSON alone, so
upgraded Trix applications keep Trix (basecamp/lexxy#1261 and rails#1262).

Applications that use Trix add gem "action_text-trix". Rendering a Trix
editor without it raises an error that says so, and the installer adds
the gem for --editor=trix, mirroring how Sprockets became an optional
dependency in Rails 7.0.

The installer also sets config.action_text.editor when --editor differs
from the configured editor, after config.load_defaults so it takes
effect, and warns about other assignments that would take precedence.

Until a Lexxy release includes basecamp/lexxy#1260, rails#1261, and rails#1262,
the Gemfile takes lexxy from a branch that combines them.
New Ruby files in app/ and lib/ declare Markdown markup, as the Markdown
API check requires.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants