RepoPilotOpen in app →

basecamp/trix

A rich text editor for everyday writing

Healthy

Healthy across the board

weakest axis
Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 2w ago
  • 10 active contributors
  • Distributed ownership (top contributor 48% of recent commits)
  • MIT licensed
  • CI configured
  • Tests present

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the “Healthy” badge

Paste into your README — live-updates from the latest cached analysis.

RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/basecamp/trix)](https://repopilot.app/r/basecamp/trix)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/basecamp/trix on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: basecamp/trix

Generated by RepoPilot · 2026-05-06 · Source

Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/basecamp/trix shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

Verdict

GO — Healthy across the board

  • Last commit 2w ago
  • 10 active contributors
  • Distributed ownership (top contributor 48% of recent commits)
  • MIT licensed
  • CI configured
  • Tests present

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live basecamp/trix repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/basecamp/trix.

What it runs against: a local clone of basecamp/trix — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in basecamp/trix | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch main exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 41 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>basecamp/trix</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of basecamp/trix. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/basecamp/trix.git
#   cd trix
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of basecamp/trix and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "basecamp/trix(\\.git)?\\b" \\
  && ok "origin remote is basecamp/trix" \\
  || miss "origin remote is not basecamp/trix (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
  && ok "default branch main exists" \\
  || miss "default branch main no longer exists"

# 4. Critical files exist
test -f "src/trix/trix.js" \\
  && ok "src/trix/trix.js" \\
  || miss "missing critical file: src/trix/trix.js"
test -f "src/trix/models/document.js" \\
  && ok "src/trix/models/document.js" \\
  || miss "missing critical file: src/trix/models/document.js"
test -f "src/trix/controllers/editor-controller.js" \\
  && ok "src/trix/controllers/editor-controller.js" \\
  || miss "missing critical file: src/trix/controllers/editor-controller.js"
test -f "src/trix/views/editor-view.js" \\
  && ok "src/trix/views/editor-view.js" \\
  || miss "missing critical file: src/trix/views/editor-view.js"
test -f "src/trix/models/attachment.js" \\
  && ok "src/trix/models/attachment.js" \\
  || miss "missing critical file: src/trix/models/attachment.js"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 41 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~11d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/basecamp/trix"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

Trix is a WYSIWYG rich text editor built as a Web Component (<trix-editor>) that treats contenteditable as an I/O device—converting user input into operations on an internal document model rather than relying on browser execCommand APIs. It outputs clean, terse HTML and ships in both ESM and UMD formats (v2.1.18) from a monorepo housing the core editor (603KB JavaScript), a Rails/Action Text gem integration, and comprehensive styling (SCSS → CSS). Monorepo structure: /src/trix/ contains the core editor engine and document model; /assets/ holds SCSS stylesheets and HTML templates; /dist/ outputs compiled UMD/ESM bundles and CSS; /action_text-trix/ is a self-contained Rails gem with a dummy test app; /test/ uses @web/test-runner for headless browser testing across Playwright/WebDriver/Sauce Labs.

Who it's for

Web developers building communication-first web apps (like Basecamp, which uses it in production with millions of users) who need a robust, cross-browser WYSIWYG editor for messages, comments, articles, and forms without fighting contenteditable quirks or maintaining complex execCommand shims.

Maturity & risk

Highly mature and production-ready: Basecamp depends on it for millions of daily users, CI runs on every commit (GitHub Actions in .github/workflows/ci.yml), comprehensive test suite via @web/test-runner + QUnit, published to npm with semantic versioning (2.1.18), and bundled in both ESM/UMD. Active maintenance with recent commits visible in build scripts and dependency updates.

Low risk for core stability but moderate maintenance surface: 27 devDependencies (Babel, Rollup, test runners, Sass compiler) increase build complexity; contenteditable behavior remains browser-dependent despite Trix's isolation strategy; the Rails gem in action_text-trix/ depends on Rails release cycles. No multi-maintainer visibility in file list, so upstream changes could create bottlenecks.

Active areas of work

Active build-system maintenance: Babel 7.16, Rollup 2.56 with terser minification, Sass compiler for CSS generation. Recent dependency updates (Concurrently 7.4, Chokidar 4.0 for watch mode). CI checks lint (ESLint) and tests on every commit. No breaking changes apparent, but version 2.x represents a major shift from legacy execCommand approach.

Get running

git clone https://github.com/basecamp/trix.git
cd trix
node -v  # Should match .node-version (if specified)
yarn install  # or npm install
yarn run build  # Builds JS, CSS, assets, and Rails gem
yarn run watch  # Continuously rebuild on file changes
yarn test       # Runs full test suite with lint check

Daily commands:

yarn run watch          # Rollup in watch mode, rebuilds on src/ changes
yarn run build          # One-time build: JS, CSS, assets, Rails gem sync
yarn run build-js       # Rollup only
yarn run build-css      # Sass only
yarn run build-ruby     # Rake sync to action_text-trix/

Map of the codebase

  • src/trix/trix.js — Main entry point for Trix editor; defines the global Trix namespace and initializes the rich text editor functionality.
  • src/trix/models/document.js — Core document model that manages the internal representation of edited text; understanding this is essential for how Trix processes content changes.
  • src/trix/controllers/editor-controller.js — Orchestrates user interactions and coordinates between the document model and view; central to the editor's control flow.
  • src/trix/views/editor-view.js — Manages the DOM representation and rendering of the editor; handles visual updates and user input capture.
  • src/trix/models/attachment.js — Handles embedded file attachments within the document; critical for understanding asset handling and serialization.
  • rollup.config.js — Build configuration for bundling Trix into UMD and ESM modules; essential for understanding the distribution pipeline.
  • .eslintrc — Linting rules defining code style and quality standards that all contributors must follow.

Components & responsibilities

  • Editor Controller (JavaScript class-based architecture) — Orchestrates user interactions, maintains editor state, delegates to document model and view; acts as the central coordinator.
    • Failure mode: Input not captured, state out of sync with DOM, commands fail silently
  • Document Model (Custom object model with Composition pattern) — Maintains internal representation of document content (text, attributes, attachments); provides immutable update API.
    • Failure mode: Document corruption, lost text on

How to make changes

Add a new formatting command (e.g., strikethrough)

  1. Define the attribute in the text attributes registry (src/trix/models/text.js)
  2. Add the toolbar button in the editor view (src/trix/views/toolbar-view.js)
  3. Implement the command handler in the editor controller (src/trix/controllers/editor-controller.js)
  4. Add CSS styling for the new format (src/trix/trix.css)
  5. Ensure HTML serializer includes the new attribute (src/trix/models/html-serializer.js)

Handle a new attachment type (e.g., video embeds)

  1. Extend the Attachment model with new type handlers (src/trix/models/attachment.js)
  2. Add preview rendering logic in the attachment view (src/trix/views/attachment-view.js)
  3. Update HTML parser to recognize the new attachment syntax (src/trix/models/html-parser.js)
  4. Update HTML serializer to output the attachment correctly (src/trix/models/html-serializer.js)
  5. Add CSS styles for the new attachment preview (src/trix/trix.css)

Customize editor appearance or behavior in Rails

  1. Create or extend a view helper in the gem (action_text-trix/lib/action_text/trix.rb)
  2. Add custom CSS overrides in your Rails app's asset pipeline (action_text-trix/app/assets/stylesheets/trix.css)
  3. Register event listeners or configure Trix in your JavaScript (action_text-trix/app/assets/javascripts/trix.js)
  4. Test using the dummy Rails application (action_text-trix/test/dummy/app/views/messages/_form.html.erb)

Why these technologies

  • Rollup bundler — Enables dual UMD and ESM module output for compatibility with both CommonJS and ES6 module consumers; tree-shaking support reduces bundle size.
  • contenteditable API (wrapped) — Provides native browser text editing foundation while Trix's document model abstracts away browser inconsistencies and bugs.
  • Rails gem wrapper (action_text-trix) — Integrates Trix seamlessly with Rails' asset pipeline and Action Text abstraction layer for RichText attributes.
  • Custom document model (not contenteditable alone) — Ensures consistent, predictable behavior across browsers and enables complex features like attachments and nested formatting without relying on browser implementation quirks.

Trade-offs already made

  • Wrapping contenteditable instead of building from scratch with canvas/virtualization

    • Why: contenteditable provides built-in accessibility, selection, and undo/redo; building from scratch would require extensive work and custom accessibility implementation.
    • Consequence: Inherits some contenteditable bugs that must be worked around; adds complexity to document model to stay in sync with DOM state.
  • Terse, intentional HTML output (custom serializer) rather than preserving all formatting

    • Why: Makes HTML portable, readable, and storage-efficient; prevents bloat from redundant style tags.
    • Consequence: Some advanced CSS styling may not round-trip; requires design discipline in supported formatting.
  • Single-repo monolith (JS editor + Rails gem) rather than separate packages

    • Why: Simplifies integration story for Rails developers and keeps editor version in sync with gem version.
    • Consequence: JS developers using non-Rails stacks must manage the JS library separately; complicates release management.

Non-goals (don't propose these)

  • Does not handle authentication or permissions—relies on host application to control who can edit.
  • Does not persist data to a database—all persistence is the responsibility of the integrating application.
  • Does not provide real-time collaborative editing—single-user editing only.
  • Does not support arbitrary HTML or CSS—only whitelisted formatting and attributes are preserved.
  • Does not provide server-side rendering of the editor UI—editor is always client-side JavaScript.
  • Does not include a file storage service—attachments must be handled by the host application via Active Storage or equivalent.

Traps & gotchas

Contenteditable volatility: Despite Trix's isolation, Safari and Firefox still have edge cases with paste/drag-drop that require browser-specific event handling—check input-controller.js. CSS build requirement: yarn build-css must run before npm publish; missing step breaks distribution. Rails gem coupling: action_text-trix/ is a separate publishable gem; changes to src/ require running yarn run build-ruby to sync compiled assets. Test environment: @web/test-runner spawns real browser instances (Playwright by default)—requires compatible Node version and browser binaries. ESM/UMD dual output: Both formats must be tested; some consumers may hit module resolution issues if only one is updated.

Architecture

Concepts to learn

  • Custom Elements / Web Components — Trix's core is a <trix-editor> custom element built on the Custom Elements API; understanding how Shadow DOM, ElementInternals, and lifecycle hooks work is essential to modifying editor behavior
  • contenteditable as I/O device — Trix's defining architectural insight: treating contenteditable as an input source, parsing user input into document mutations, then re-rendering—avoiding reliance on unstable execCommand APIs across browsers
  • Mutation Observer — Trix uses MutationObserver to detect changes the browser makes to contenteditable in real-time, triggering re-validation against the internal document model
  • Internal document model pattern — Trix maintains a parallel document tree (src/trix/models/) separate from the DOM; changes flow through input → model → DOM re-render, giving Trix complete control over editor state
  • ElementInternals API — Trix uses ElementInternals to integrate <trix-editor> with HTML form submission and validation, making it behave like a native <textarea> or <input>
  • Rollup bundling with dual ESM/UMD output — Trix ships both ES modules (for modern bundlers) and UMD (for <script> tags); understanding rollup.config.js and the dual-build strategy is critical for distribution and breaking changes
  • Text composition events — Trix must handle IME (Input Method Editor) composition on Asian keyboards and dead-key sequences; composition events (compositionstart, compositionend) prevent premature document mutations during partial input

Related repos

  • rails/rails — Home of Action Text, Rails' built-in rich text handling—Trix is the default editor and action_text-trix/ gem integrates directly into Rails asset pipeline
  • ProseMirror/prosemirror-core — Alternative CRDT-based rich text editor with similar philosophy of custom document model, but more framework-like and less opinionated on styling
  • ianstormtaylor/slate — React-focused rich text library with pluggable architecture; competes on flexibility but requires React (Trix is framework-agnostic)
  • basecamp/action_text — The Rails native rich text storage and ORM abstraction that pairs with Trix editor; handles database persistence and attachment management
  • tinymce/tinymce — Legacy WYSIWYG editor based on execCommand; represents the older approach that Trix was designed to replace

PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add system tests for the Rails action_text-trix gem integration

The action_text-trix subdirectory contains a Rails engine with a dummy test app (test/dummy/) including a MessagesController and message views with Trix editor forms, but there are no visible system/integration tests. The test/application_system_test_case.rb exists but appears empty. This is critical for ensuring the gem works correctly with Rails' ActionText when integrated into real applications.

  • [ ] Review test/application_system_test_case.rb and test/dummy/app/views/messages/_form.html.erb to understand the integration points
  • [ ] Create action_text-trix/test/system/message_editing_test.rb with system tests for creating/editing messages with Trix
  • [ ] Add tests covering: toolbar functionality, attachment upload flow, HTML output validation, and form submission
  • [ ] Ensure tests run in the pretest npm script workflow alongside existing lint/build steps

Add comprehensive CSS regression tests for Trix editor styling

The repo builds CSS from assets/trix.scss into dist/trix.css and action_text-trix/app/assets/stylesheets/trix.css, but there are no visual regression tests. Given that Trix is a visual WYSIWYG editor used by millions, ensuring CSS doesn't break across versions is critical. The .github/workflows/ci.yml and @web/test-runner setup suggest the infrastructure is partially there.

  • [ ] Review assets/trix.scss and dist/trix.css to identify key visual components (toolbar, editor area, formatting buttons)
  • [ ] Add a new test file test/css-regression.test.js using @web/test-runner with visual snapshot testing (e.g., Percy or similar)
  • [ ] Create test cases for: toolbar button states, text formatting appearance, placeholder styling, and responsive breakpoints
  • [ ] Document the visual regression testing setup in README.md for contributors

Add TypeScript type definitions and JSDoc coverage for core Trix modules

The main entry point is dist/trix.esm.min.js and dist/trix.umd.min.js (built from src/), but there are no .d.ts files or comprehensive JSDoc comments in the source. With the npm package having both ESM and UMD outputs, consumers (especially TypeScript projects) lack IDE autocomplete and type safety. This improves developer experience significantly.

  • [ ] Audit src/trix/.js and src/inspector/.js to identify public API surface (e.g., Trix.Editor, Trix.Document, etc.)
  • [ ] Add JSDoc comments with @param, @returns, @typedef annotations for all public classes and methods in source files
  • [ ] Generate a trix.d.ts declaration file or configure package.json to point to generated types (e.g., via @babel/plugin-transform-typescript or rollup-plugin-dts)
  • [ ] Test TypeScript integration by creating a simple test-types.ts file and running tsc --noEmit

Good first issues

  • idea: Add JSDoc type annotations to src/trix/models/*.js files (Document.js, Fragment.js, Attachment.js) to improve IDE autocomplete and documentation—many classes lack formal type contracts.
  • idea: Expand test coverage in /test/ for edge cases in input-controller.js (currently testing main paths but missing browser-specific paste/drop scenarios on Safari/Firefox)—add browser-specific test suites.
  • idea: Write a migration guide from Trix 1.x (execCommand-based) to 2.x (internal document model)—README mentions v2 is different but lacks concrete before/after examples of API changes affecting existing users.

Top contributors

Recent commits

  • da88699 — v2.1.18 (flavorjones)
  • 9c0a993 — Fix XSS via javascript: URI in JSON drag-drop deserialization (#1293) (flavorjones)
  • e62fcc3 — ci: harden GitHub Actions workflows (#1284) (flavorjones)
  • 2e46d51 — v2.1.17 (flavorjones)
  • 53197ab — Merge pull request #1282 from basecamp/h1-3581911-serialized-attr (flavorjones)
  • 3229c29 — Fix stored XSS via data-trix-serialized-attributes sanitizer bypass (H1 #3581911) (flavorjones)
  • 7069343 — Merge pull request #1239 from Cromian/patch-1 (flavorjones)
  • d9dbf0a — Merge pull request #1280 from basecamp/fix-bullets-merging-with-prior-element (flavorjones)
  • bef13e2 — Fix bullets merging with prior elements when the first node is removed (monorkin)
  • 194a36c — Merge pull request #1275 from basecamp/flavorjones/wtr-failure-messages (flavorjones)

Security observations

  • High · Outdated Babel Dependencies — package.json - devDependencies. The package.json includes @babel/core@^7.16.0 and @babel/preset-env@^7.16.4, which are significantly outdated (released in 2021). These versions may contain known security vulnerabilities and lack security patches released in newer versions. Fix: Update Babel to the latest stable version (^7.23.0 or higher). Run 'npm audit' to identify specific vulnerabilities and update all dependencies to their latest versions.
  • High · Outdated ESLint Version — package.json - devDependencies. ESLint version ^7.32.0 is outdated (released in 2021). While not a production dependency, outdated linters may miss security issues and patterns that newer versions catch. Fix: Upgrade ESLint to version ^8.0.0 or higher to benefit from improved security checks and linting rules.
  • High · Outdated Rollup and Build Tool Dependencies — package.json - devDependencies (rollup and @rollup/* packages). Multiple build tool dependencies are outdated: rollup@^2.56.3, @rollup/plugin-babel@^5.3.0, and others from 2021. Outdated build tools may have unpatched vulnerabilities that could be exploited during the build process. Fix: Update rollup to ^3.0.0 or higher and all @rollup/* plugins to their latest versions. This ensures security patches and improved build process integrity.
  • High · Outdated Testing Dependencies — package.json - devDependencies (@web/* packages). @web/test-runner@^0.20.2 and related testing packages (@web/dev-server, @web/test-runner-playwright) are outdated. Testing infrastructure vulnerabilities can compromise CI/CD pipelines. Fix: Update @web/test-runner and related packages to the latest versions (^0.18.0+). Ensure all test runner dependencies are current.
  • Medium · Potential XSS Risk in Rich Text Editor — src/trix/*.js and dist/trix.umd.min.js. Trix is a WYSIWYG editor that processes and outputs HTML. While the project appears well-maintained, rich text editors are historically prone to XSS vulnerabilities. The codebase needs careful review of HTML sanitization routines, especially in areas handling user-generated content and embedded attachments. Fix: Ensure all HTML output is properly sanitized. Implement Content Security Policy headers. Add security-focused unit tests for XSS prevention. Consider using a whitelist-based HTML sanitizer for user-generated content.
  • Medium · Outdated WebdriverIO for Testing — package.json - devDependencies and resolutions. webdriverio@^7.19.5 is outdated (from 2023). This testing dependency may have unpatched security issues affecting the CI/CD pipeline. Fix: Update webdriverio to the latest stable version. The explicit resolution for webdriverio suggests there may have been dependency conflicts; ensure this is resolved with the latest version.
  • Medium · Missing npm Audit Configuration — .github/workflows/ci.yml. No visible npm audit or dependency scanning configuration in GitHub workflows (.github/workflows/ci.yml content not shown). The project should enforce dependency security checks in CI/CD. Fix: Add 'npm audit' or 'yarn audit' to the CI/CD pipeline to fail builds on high/critical vulnerabilities. Use automated dependency updates via Dependabot (already configured) combined with security scanning.
  • Medium · Outdated Sass Compiler — package.json - devDependencies. sass@^1.83.0 should be verified to be the latest version. Build tool vulnerabilities can introduce security issues into the compiled assets. Fix: Verify sass is updated to the latest version. Run 'yarn upgrade sass' to ensure the latest security patches are applied.
  • Low · Babel ESLint Deprecation — undefined. babel-eslint@^10.1.0 is deprecated in favor of @babel/ Fix: undefined

LLM-derived; treat as a starting point, not a security audit.

Where to read next


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.