A modular, framework-agnostic rich-text editor for modern browsers
  • TypeScript 98.9%
  • JavaScript 0.6%
  • HTML 0.3%
  • CSS 0.2%
Find a file
Martin Burchard 43e44974a0
All checks were successful
CI / ci (push) Successful in 4m49s
fix: stabilize browser editing across engines
Install Playwright system dependencies in CI for the Trixie runner.
Track undo and redo availability through editor-local DOM history.
Preserve explicit left alignment across block replacement, undo, and redo.
Avoid browser-dependent assumptions about disabled controls and native undo grouping.
2026-08-31 21:43:57 +02:00
.forgejo/workflows fix: stabilize browser editing across engines 2026-08-31 21:43:57 +02:00
lib fix: stabilize browser editing across engines 2026-08-31 21:43:57 +02:00
playground feat: add standard editor presets 2026-08-31 09:50:31 +02:00
test feat: add standard editor presets 2026-08-31 09:50:31 +02:00
.editorconfig chore: initialize bit-editor tooling 2026-08-26 13:13:35 +02:00
.gitignore Add initial editor surface 2026-08-27 15:41:05 +02:00
.node-version chore: initialize bit-editor tooling 2026-08-26 13:13:35 +02:00
CHANGELOG.md feat: add standard editor presets 2026-08-31 09:50:31 +02:00
eslint.config.js chore: initialize bit-editor tooling 2026-08-26 13:13:35 +02:00
LICENSE chore: initialize bit-editor tooling 2026-08-26 13:13:35 +02:00
package.json feat: add standard editor presets 2026-08-31 09:50:31 +02:00
pnpm-lock.yaml Add initial editor surface 2026-08-27 15:41:05 +02:00
pnpm-workspace.yaml chore: initialize bit-editor tooling 2026-08-26 13:13:35 +02:00
README.md feat: add standard editor presets 2026-08-31 09:50:31 +02:00
tsconfig.build.json chore: initialize bit-editor tooling 2026-08-26 13:13:35 +02:00
tsconfig.consumer.json chore: initialize bit-editor tooling 2026-08-26 13:13:35 +02:00
tsconfig.json chore: initialize bit-editor tooling 2026-08-26 13:13:35 +02:00
vitest.config.ts Add initial editor surface 2026-08-27 15:41:05 +02:00

bit-editor

A modular, framework-agnostic rich-text editor for modern browsers.

bit-editor is being designed as a Vanilla TypeScript library with native ESM output. It will provide a small, auditable editor core without a framework runtime dependency, global registration, telemetry, or implicit network access.

Status

The first editing surface is available. It supports paragraphs, configurable semantic headings, soft line breaks, optional inline formatting and text alignment, a modular toolbar, and sanitized clipboard operations while blocking drop and unsupported formatting operations.

Design Goals

  • Work consistently on desktop browsers, iPadOS, and Android tablets.
  • Keep the editor core independent of Vue, React, and other UI frameworks.
  • Make supported document structures and formatting explicitly configurable.
  • Apply the same schema rules to input, paste, copy, normalization, and serialization.
  • Keep commands, schema extensions, and editing behaviour modular and tree-shakeable.
  • Ship native ESM modules and TypeScript declarations without a pre-bundled runtime.
  • Maintain 100% line, statement, function, and branch coverage through behaviour-focused tests.

Requirements

Development requires Node.js 24 and pnpm 11.

Install the browser engines used by the DOM behaviour tests once after installing dependencies:

pnpm exec playwright install chromium firefox webkit

Quick Start

<div id="editor-toolbar"></div>
<div id="editor" aria-label="Article content"></div>
import {useEditor} from '@mburchard/bit-editor';

const element = document.querySelector<HTMLElement>('#editor');
const toolbarElement = document.querySelector<HTMLElement>('#editor-toolbar');
if (!element || !toolbarElement) {
  throw new TypeError('The editor or toolbar element is missing');
}

const instance = useEditor(element, toolbarElement);

The standard preset matches the playground toolbar without HTML source mode. Import useHtmlEditor from @mburchard/bit-editor/html when source editing is required. The granular createEditor and createToolbar APIs remain available for custom schemas and toolbars.

The editor uses the supplied element directly and marks it with data-bit-editor-root. Enter creates a paragraph, and Shift+Enter creates a soft line break. Pass {enterMode: 'line-break'} to make Enter create a line break as well. The editor sets the document-wide native paragraph separator to p. Ordered and unordered lists are enabled by default and support nesting with Tab and Shift+Tab. Pass listTypes to limit the allowed types or disable lists. Disallowed list markup is converted to paragraphs during sanitization. H1 through H3 are enabled by default. Pass headingLevels to support any chosen combination of H1 through H6, and provide matching headings entries to headingSelect when the toolbar should expose a custom set. When a heading selector is present, it must expose every heading level enabled by the editor. Toolbar creation throws a TypeError describing missing or unsupported levels when the configurations differ. Text alignment is opt-in through textAlignments; add matching alignment actions to expose it in the toolbar. Block indentation is opt-in through indentation; each command step uses a logical 0.5rem margin. The optional toolbar injects its functional base styles once per document and exposes scoped data attributes and CSS custom properties for application styling. The application owns the editor's accessible name and visual design. Undo and redo commands use the browser's native editing history in visual and source mode. Initial content may be empty, direct text, or configured paragraphs and headings containing text, line breaks, and configured inline formats.

Call instance.destroy() to remove preset controls and listeners and restore the attributes owned by bit-editor. Edited content remains in the editor element.

Development

pnpm install
pnpm lint
pnpm typecheck
pnpm test:firefox
pnpm test:webkit
pnpm coverage
pnpm package:check
pnpm playground:check

package:check performs a package dry run, which builds the native ESM package through prepack, then validates it from a consumer project and checks that an unused package import contributes no runtime code to a browser bundle. Pure library tests run in Node.js, editing-surface coverage runs in real Chromium, and the same behaviour suite runs in Firefox and WebKit as compatibility checks.

Playground

The private playground workspace package exercises bit-editor directly from a Vanilla TypeScript and Vite consumer while keeping Vite and bit-log out of the editor package dependencies and published tarball.

pnpm playground:dev

The command builds bit-editor before starting the playground, so the page consumes the same package exports that an external application would use.

Framework Integration

Framework integrations do not belong to the editor runtime or its Vanilla playground. A separate Vue demonstration will later show how to wrap the Vanilla TypeScript API in a Vue component without adding Vue as a dependency or peer dependency to the editor package.