RepoPilotOpen in app →

jaredreich/pell

📝 the simplest and smallest WYSIWYG text editor for web, with no dependencies

Mixed

Stale — last commit 2y ago

weakest axis
Use as dependencyFailing

last commit was 2y ago; top contributor handles 94% of recent commits…

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-isMixed

last commit was 2y ago; no CI workflows detected

  • 5 active contributors
  • MIT licensed
  • Stale — last commit 2y ago
  • Single-maintainer risk — top contributor 94% of recent commits
  • No CI workflows detected
  • No test directory detected
What would change the summary?
  • Use as dependency FailingMixed if: 1 commit in the last 365 days
  • Deploy as-is MixedHealthy if: 1 commit in the last 180 days

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.

Earn the “Healthy” badge

Current signals for jaredreich/pell are Mixed. The embed flow is reserved for repos showing Healthy signals — the rest stay informational on this page so we're not putting a public call-out on your README. Address the items in the What would change the summary? dropdown above, then return to grab the embed code.

Common quick wins: green CI on default branch, no Critical CVEs in dependencies, recent commits on the default branch, a permissive license, and a published README.md with a quickstart.

Onboarding doc

Onboarding: jaredreich/pell

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/jaredreich/pell 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

WAIT — Stale — last commit 2y ago

  • 5 active contributors
  • MIT licensed
  • ⚠ Stale — last commit 2y ago
  • ⚠ Single-maintainer risk — top contributor 94% of recent commits
  • ⚠ No CI workflows detected
  • ⚠ No test directory detected

<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 jaredreich/pell repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/jaredreich/pell.

What it runs against: a local clone of jaredreich/pell — 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 jaredreich/pell | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 754 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>jaredreich/pell</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of jaredreich/pell. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/jaredreich/pell.git
#   cd pell
#
# 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 jaredreich/pell and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "jaredreich/pell(\\.git)?\\b" \\
  && ok "origin remote is jaredreich/pell" \\
  || miss "origin remote is not jaredreich/pell (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 master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "src/pell.js" \\
  && ok "src/pell.js" \\
  || miss "missing critical file: src/pell.js"
test -f "src/pell.scss" \\
  && ok "src/pell.scss" \\
  || miss "missing critical file: src/pell.scss"
test -f "dist/pell.min.js" \\
  && ok "dist/pell.min.js" \\
  || miss "missing critical file: dist/pell.min.js"
test -f "package.json" \\
  && ok "package.json" \\
  || miss "missing critical file: package.json"
test -f "gulpfile.js" \\
  && ok "gulpfile.js" \\
  || miss "missing critical file: gulpfile.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 754 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~724d)"
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/jaredreich/pell"
  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

Pell is a 3.54kB minified WYSIWYG text editor library written in vanilla ES6 JavaScript with zero dependencies, built on the contenteditable HTML API. It provides 15 common formatting actions (bold, italic, headings, lists, links, images, etc.) and ships pre-compiled CSS in dist/pell.min.css for immediate use via CDN or npm. Simple single-package structure: src/pell.js is the core editor engine (~6.2kB raw), src/pell.scss defines all UI styling (~1kB), Gulpfile.js orchestrates Babel+Rollup transpilation/bundling into dist/, and demo.html provides a working example. No subdirectories or monorepo complexity—intentionally minimal.

Who it's for

Frontend developers building lightweight web applications who need rich text editing without the 43kB+ overhead of Quill, Draft.js, or TinyMCE. Particularly valuable for projects with strict bundle size constraints or those targeting minimal dependencies (JAMstack, static site generators, simple CMS interfaces).

Maturity & risk

Pell is stable and production-ready at v1.0.6 with established npm/CDN distribution, but development appears semi-active—a v2 branch exists with a project board, suggesting planned improvements rather than abandonment. No obvious CI/testing infrastructure visible in the file list; relies on manual builds via Gulp and eslint for code quality.

Single-maintainer project (Jared Reich) with minimal visible test suite or CI/CD pipeline increases maintenance risk. The v2 project board suggests breaking changes may be coming. Build tooling depends on older Gulp 3.9.1 and Rollup 0.45.1 (modern versions are significantly different), which could cause friction during dependency updates.

Active areas of work

A v2 branch is active with its own project board tracking improvements. The main branch is at v1.0.6. Specific recent work is not visible in the file list alone, but the existence of planned v2 work suggests bug fixes, feature additions (possibly new actions or API improvements), and modernization of build tooling are under consideration.

Get running

git clone https://github.com/jaredreich/pell.git
cd pell
npm install
npm run dev

The npm run dev command launches the Gulp watcher. For a production build: npm run build. Open demo.html in a browser to test the editor immediately.

Daily commands: npm run dev watches src/ and rebuilds dist/ on changes via Gulp. npm run build performs a full clean build. npm run lint checks code style with eslint-config-jared. Open demo.html in a browser to interact with the editor.

Map of the codebase

  • src/pell.js — Core editor implementation—all WYSIWYG functionality, command execution, and DOM manipulation logic lives here.
  • src/pell.scss — Stylesheet for the editor UI; defines toolbar layout, button styling, and contenteditable area appearance.
  • dist/pell.min.js — Minified production bundle that end-users load; this is the actual distributed artifact from npm/CDN.
  • package.json — Defines build pipeline (Babel, Gulp), version, and npm distribution config—required for releases.
  • gulpfile.js — Build orchestration: compiles ES6 to ES5, minifies JS/CSS, and manages dist/ outputs.
  • demo.html — Standalone demo page showing how to instantiate and use the editor in a real HTML context.

Components & responsibilities

  • Editor Core (src/pell.js) (JavaScript, DOM API, contenteditable, execCommand) — Initializes editor, manages toolbar, handles command dispatch, binds input/click events
    • Failure mode: If pell.init() is not called or passed invalid config, editor does not render; if execCommand fails, formatting may not apply (browser-dependent)
  • Toolbar UI (HTML, CSS (src/pell.scss), DOM event listeners) — Renders action buttons, applies styling, responds to clicks
    • Failure mode: If CSS fails to load, buttons appear unstyled; if event listeners don't attach, clicks are ignored
  • Contenteditable Area (contenteditable attribute, browser text selection API, execCommand) — Receives user input, applies formatting via execCommand, emits text for retrieval
    • Failure mode: If contenteditable is disabled or browser doesn't support it, text input and formatting fail; execCommand failures vary by browser
  • Build Pipeline (gulpfile.js + Babel + Sass) (Gulp, Babel, Sass, Node.js) — Transpiles, minifies, and outputs distribution artifacts
    • Failure mode: If build fails, dist/ artifacts are stale or missing; users may receive old or broken code

Data flow

  • User (keyboard/mouse)Browser (DOM + contenteditable) — User types text or clicks toolbar buttons; browser captures input and forwards to event listeners
  • Browser event listenerpell.js command handler — Click or input event triggers corresponding action in pell editor; maps to execCommand call or internal state update
  • pell.jsdocument.execCommand() — Editor calls execCommand with command name (bold, italic, etc.) and optional value (URL for link, color, etc.

How to make changes

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

  1. Open src/pell.js and locate the exec() function or command handler switch statement. Add a new command case (e.g., 'strikethrough' → document.execCommand('strikeThrough')) (src/pell.js)
  2. Add a new button definition in the actions configuration object, specifying the command name, icon/text, and title (src/pell.js)
  3. If visual styling is needed, add CSS rules in src/pell.scss targeting the new button class (src/pell.scss)
  4. Run npm run build to transpile and minify, then test in demo.html (gulpfile.js)

Customize toolbar buttons or disable features

  1. In demo.html (or your app), pass actions array to pell.init() config to override default toolbar layout (demo.html)
  2. Reference src/pell.js to see available action definitions (bold, italic, underline, strikethrough, heading1–2, paragraph, quote, olist, ulist, code, line, link, image) (src/pell.js)
  3. Include or exclude actions in your config object: { element: ..., actions: [pell.PellAction.bold, pell.PellAction.italic, ...] } (demo.html)

Integrate pell into a React or Vue app

  1. Refer to examples/react.md or examples/vue.md for framework-specific setup and lifecycle handling (examples/react.md)
  2. Install pell via npm: npm install pell, then import { init } from 'pell' (package.json)
  3. Call pell.init({ element: ref, ... }) once the DOM element mounts; retrieve editor content via element.innerHTML (demo.html)

Why these technologies

  • contenteditable attribute — Browser-native rich-text editing with minimal code; no need to build a text parser or renderer from scratch.
  • document.execCommand() — Standard DOM API for formatting operations (bold, italic, heading, etc.) with broad browser support and no external dependencies.
  • Babel ES2015 transpiler — Allows modern JavaScript (ES6) in src/pell.js while maintaining compatibility with older browsers via ES5 output.
  • Gulp build system — Simple, lightweight task automation for minification and asset bundling; pairs well with a small, single-file project.
  • Sass for CSS preprocessing — Modular styling with variables and nesting; compiles to standard CSS with zero runtime overhead.

Trade-offs already made

  • Zero runtime dependencies

    • Why: Keeps bundle size minimal (1.38 kB gzip) and dependency tree simple; maximizes portability.
    • Consequence: No advanced features (collaborative editing, conflict resolution, undo/redo stack); users must implement these if needed.
  • Rely on document.execCommand()

    • Why: Simplicity and native browser support; avoids rewriting rich-text logic.
    • Consequence: Browser inconsistencies in execCommand behavior; limited control over generated HTML structure; deprecated in some future specs.
  • Single src/pell.js file

    • Why: Extreme simplicity; easy to understand and fork.
    • Consequence: Less modular; large number of concerns (UI, event handling, command logic) in one file; harder to refactor without breaking changes.
  • No built-in content validation or sanitization

    • Why: Keeps scope and bundle size minimal.
    • Consequence: Users are responsible for sanitizing HTML output before storing or displaying; risk of XSS if used carelessly.

Non-goals (don't propose these)

  • Collaborative real-time editing (no operational transform or CRDT)
  • Undo/redo management (browser's native undo handles some cases, but not guaranteed)
  • Advanced accessibility (ARIA labels, keyboard navigation) beyond basic contenteditable defaults
  • Server-side rendering or SSR support
  • Content validation, sanitization, or schema enforcement
  • Plugin system or extensibility framework

Traps & gotchas

No hidden environment variables or service dependencies. However: (1) The build process uses Gulp 3.x API which differs significantly from Gulp 4+—upgrading will require rewriting the gulpfile. (2) Babel 6 preset configuration in .babelrc is locked to es2015/stage-0—modern Babel 7+ migration would be needed for ES2020+ syntax. (3) Rollup 0.45.1 is very old; modern Rollup versions have different plugin APIs. (4) No test files are visible—testing must be manual or external.

Architecture

Concepts to learn

  • contenteditable API — Pell's entire editor logic depends on the native HTML contenteditable attribute and document.execCommand()—understanding these browser APIs is essential to modifying action behavior or debugging formatting issues
  • Rollup ES module bundling — The build process uses Rollup (src/pell.js → dist/pell.js + minified version) to transpile ES6 to ES5 and tree-shake unused code—understanding this is necessary to extend the editor or modify the build pipeline
  • Babel transpilation (ES6 to ES5) — The project is written in modern ES6 but must support IE9+, so Babel transforms arrow functions, const/let, and classes into older syntax—this explains the .babelrc configuration and build complexity
  • SCSS mixins and variable scoping — pell.scss uses SCSS features (nesting, variables) to keep styling DRY and maintainable—understanding how .pell-content, .pell-button, and .pell-input classes are generated helps with customization
  • Gzip compression metrics for bundle size — Pell's key selling point is its 1.38kB gzipped size versus competitors (Quill: 43kB, TinyMCE: 157kB)—understanding why minification and gzip compression matter helps justify trade-offs between features and bundle size
  • Document fragment and DOM manipulation — The action system likely uses DOM methods to insert elements (links, images, hr) into the contenteditable area—familiarity with appendChild, insertNode, and innerHTML helps when adding or debugging custom actions
  • CSS custom properties (CSS variables) for theming — While pell.scss predates modern CSS variables, overriding .pell-* class styles is the primary customization path—understanding the class hierarchy and selector specificity is necessary to theme without forking the library

Related repos

  • quilljs/quill — Industry-standard rich text editor (43kB min+gzip) with more features and plugin ecosystem, directly compared in pell's size benchmark table
  • neilj/Squire — Lightweight contenteditable wrapper (16kB min+gzip) positioned as a minimalist alternative; shares similar philosophy but larger footprint
  • basecamp/trix — Basecamp's WYSIWYG editor (47kB min+gzip) with built-in attachment handling; represents the Rails/full-featured alternative
  • Alex-D/Trumbowyg — Lightweight jQuery-dependent editor (8kB min+gzip) from the same minimal-footprint category, useful reference for comparison
  • yabble/medium-editor — Medium.com-inspired inline editor (27kB min+gzip) that influenced modern lightweight editor design patterns

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 GitHub Actions CI workflow for linting and build verification

The repo has eslint configured (.eslintrc, .eslintignore) and build scripts (gulpfile.js) but no CI/CD pipeline. A new contributor could add a GitHub Actions workflow that runs npm run lint and npm run build on every PR to catch issues early. This is especially valuable since the package.json lint script has a glob pattern issue (.js ./ appears incomplete).

  • [ ] Create .github/workflows/ci.yml with Node.js setup
  • [ ] Add lint job running eslint against src/ and examples/
  • [ ] Add build job running gulp clean && gulp script && gulp style
  • [ ] Verify dist/ artifacts are generated without errors
  • [ ] Test workflow triggers on pull_request and push to main

Add unit tests for core src/pell.js functionality

The repo has no test files despite being a published npm package (v1.0.6). Critical editor functions like init(), execute(), setContent(), and getContent() lack test coverage. A new contributor could create a test suite using Jest or Mocha to validate core APIs, catching regressions as the library evolves toward v2.

  • [ ] Choose test framework (Jest recommended for minimal setup)
  • [ ] Create test/pell.test.js with tests for init() initialization
  • [ ] Add tests for execute() command execution (bold, italic, link, etc.)
  • [ ] Add tests for setContent() and getContent() methods
  • [ ] Add tests for event handling (onChange callback)
  • [ ] Update package.json with test script: 'test': 'jest'

Create API documentation for src/pell.js in docs/API.md

The README mentions examples for React and Vue (examples/react.md, examples/vue.md) but no formal API documentation exists. The main source file src/pell.js lacks inline JSDoc comments and users must read source code to understand the public API. A new contributor could document all exported functions, their parameters, return values, and usage examples in a dedicated docs file.

  • [ ] Create docs/API.md with sections for each public method
  • [ ] Document pell.init(config) with all config options and examples
  • [ ] Document pell.execute(command, value) with command reference table
  • [ ] Document pell.setContent() and pell.getContent() methods
  • [ ] Add usage examples for basic setup and common commands
  • [ ] Link to docs/API.md from main README.md

Good first issues

  • Add a test suite: Create src/tests/ directory and write unit tests for action execution (bold, italic, link creation) using a testing framework like Jest, with mock contenteditable elements to verify document.execCommand() calls are correct.
  • Document integration examples: The examples/ folder lists React and Vue integration guides in Markdown, but they appear incomplete or missing working code—expand examples/react.md and examples/vue.md with runnable component snippets showing how to mount Pell inside React hooks or Vue 3 composition API.
  • Create TypeScript type definitions: Add pell.d.ts to the dist/ folder to provide IDE autocomplete and type safety for users installing via npm. The README lists available actions like justifyCenter and superscript, but no types exist—defining the action names and init() config object would help developers discover the API.

Top contributors

Recent commits

  • d5556ba — Remove personal website from repo. (jaredreich)
  • 49a7f63 — Add v2 info to README. (jaredreich)
  • 4303014 — Update README. (jaredreich)
  • bb96a86 — Bump version to 1.0.6 (jaredreich)
  • b492cf6 — Add dist files for v1.0.5 (jaredreich)
  • f114da0 — Bump version to 1.0.5 (jaredreich)
  • d82e1b6 — Merge branch 'master' of https://github.com/jaredreich/pell (jaredreich)
  • 0233850 — allow tab key input (fixes jaredreich/pell#66, satisfies WCAG 2.1.2) (#155) (geppy)
  • 97e7cac — Add example for Vue (jaredreich)
  • ffcd192 — Add React example to README. (jaredreich)

Security observations

This codebase has significant security concerns primarily due to severely outdated dependencies from 2017. The main risks include: (1) Critical: Multiple high-severity vulnerabilities in Babel, Gulp, Rollup, and associated build tools; (2) High: Lack of security tooling and automated vulnerability scanning; (3) Medium: Potential XSS risks inherent to WYSIWYG editors handling user content. The project requires immediate dependency updates to current versions and implementation of proper content sanitization practices for the rich text editor functionality.

  • High · Outdated Babel Dependencies with Known Vulnerabilities — package.json - devDependencies: babel-core, babel-preset-es2015, babel-preset-stage-0. The project uses babel-core 6.23.1 and related preset packages from January 2017. These versions contain known security vulnerabilities and lack security patches. Babel 6.x reached end-of-life and should be upgraded to Babel 7.x or later. Fix: Upgrade to Babel 7.x (latest stable version). Update babel-core, @babel/core, and related presets to their latest versions.
  • High · Outdated Build Tool Dependencies — package.json - devDependencies: gulp, rollup, gulp-rollup, rollup-plugin-babel, rollup-plugin-uglify. gulp (3.9.1), rollup (0.45.1), and related plugins are severely outdated (from 2017). These versions contain known security vulnerabilities in transitive dependencies and lack security updates. Gulp 3.x reached EOL. Fix: Upgrade to latest stable versions: gulp 4.x or higher, rollup 2.x or higher, and all associated plugins to their current versions.
  • High · Outdated ESLint Configuration — package.json - devDependencies: eslint-config-jared. The ESLint configuration package (eslint-config-jared 1.2.0) is outdated and may not enforce current security best practices. The main eslint package version is not specified, potentially using an old version. Fix: Update eslint and eslint-config-jared to latest versions. Consider using a modern, maintained ESLint configuration like eslint-config-airbnb or eslint-config-google.
  • Medium · Potential XSS Vulnerability in WYSIWYG Editor — src/pell.js (requires code review). As a WYSIWYG text editor using contenteditable, the application handles rich text content. Without proper sanitization, user-generated content could be vulnerable to XSS attacks if the editor output is not properly escaped when stored or rendered elsewhere. Fix: Implement proper HTML sanitization using libraries like DOMPurify before storing or rendering user-generated content. Ensure all output is properly escaped when inserted into the DOM.
  • Medium · Missing npm Audit and Security Scanning — package.json - scripts section. No security audit scripts (npm audit, npm audit fix) are configured in the package.json. There's no automated security scanning in the build process or CI/CD pipeline visible. Fix: Add 'audit' script: '"npm audit"' and integrate security scanning into CI/CD. Consider using tools like Snyk or npm audit for continuous vulnerability monitoring.
  • Low · Package Lock File Outdated — package-lock.json. The presence of package-lock.json with old dependency versions indicates the lockfile is significantly outdated. This could lead to inconsistent builds and missed security updates. Fix: Delete package-lock.json and regenerate it with 'npm install' after updating all dependencies to current versions. Use npm ci in production environments.
  • Low · No Security Headers or CSP Configuration — demo.html and web server configuration. The demo.html file and static assets appear to lack Content Security Policy headers or other security headers that would help mitigate XSS and other injection attacks. Fix: Implement proper security headers including Content-Security-Policy, X-Content-Type-Options, X-Frame-Options, and X-XSS-Protection in the web server configuration.

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.

Mixed signals · jaredreich/pell — RepoPilot