scribejs-editor
v1.0.1
Published
Lightweight, plugin-first rich text editor core with a fixed toolbar demo and typed API.
Maintainers
Readme
Scribe Editor
Lightweight rich-text editor core with a modern demo UI, fixed toolbar workflow, and a minimal API.
Website: https://scribejs.top
What's new in v1.0.1
Cross-browser toolbar fixes
Toolbar state (bold / italic / underline / strike / etc.) is now identical across Chrome, Firefox, and Safari.
Selection handling
- Normalized selection layer abstracts
window.getSelection()andRangedifferences. - Handles collapsed, backward, multi-node, and text-vs-element selections uniformly.
- Full iframe editing context support via
ownerDocument.defaultView.
Toolbar state detection
- No longer relies on deprecated
document.queryCommandState/queryCommandValue. - Walks the DOM tree from the selection range, inspecting parent nodes for active marks (
<b>,<strong>,<i>,<em>,<u>,<s>,<strike>,<code>,<a>,<blockquote>,<ol>,<ul>, headings). - Alignment detected via
getComputedStylewith cross-window safety.
Safari fixes
- Selection saved before every toolbar click and restored after action.
- Prevents selection reset that Safari applies on button focus.
Firefox fixes
selectionchangetiming gaps handled via multi-event pipeline (formatChange,change,focus,blur).- Mutation-safe selection refresh on every DOM change.
Polling safety net
- 100 ms interval while editor is focused force-refreshes
FormatStatefromSelectionManager. - JSON-diff guard ensures React only re-renders when state actually changes.
- Interval stops on blur and cleans up on unmount.
Event model
- Supports
selectionchange,beforeinput,input,keyup,mouseup. formatChangeevent emitted synchronously after every command execution and DOM normalization.
Command registry
- All toolbar items driven by
CommandMeta— icon, label, shortcut, group,active()function. - Fixed and floating toolbars share the same metadata; no duplicated logic.
DOM normalizer (5-phase pipeline)
- Structural cleanup (empty nodes, whitespace)
- Inline mark merging (adjacent
<b><b>→ single<b>) - Block-level normalization
- List structure repair
- Final whitespace pass
Table of contents
Features
- Inline-first editing with a fixed toolbar experience.
- Simple, typed API with direct method calls.
- Built-in HTML sanitization and safe paste handling.
- Extensible plugin architecture.
- Framework-agnostic core for integration anywhere.
Screenshots
| API | Inline Toolbar | Fixed Editor |
| --- | --- | --- |
|
|
|
|
Download
- NPM:
npm i scribejs-editor - CDN:
https://unpkg.com/scribejs-editor - Git:
git clone https://github.com/GoodPHP/scribejs
Usage
import { createEditor } from 'scribejs-editor';
const editor = createEditor({
target: '#editor',
placeholder: 'Start typing...'
});
editor.bold();
editor.link('https://example.com');
const html = editor.getHTML();React wrapper
import { ScribeEditor, type ScribeEditorRef } from './components/scribe';
import { useRef } from 'react';
function App() {
const editorRef = useRef<ScribeEditorRef>(null);
return (
<ScribeEditor
ref={editorRef}
toolbar="fixed"
placeholder="Write something..."
onChange={(html) => console.log(html)}
/>
);
}Development
npm install
npm run devWhen the dev server starts, it prints the local URL to open the demo.
Documentation
- Demo UI: index.html + public/demo.css + public/demo.js
- Build output: dist/index.js (browser ESM)
- Types: types/index.d.ts
- Source: src/
API
Common editor methods used in the demo:
editor.bold()/editor.italic()/editor.underline()editor.heading(1 | 2 | 3)/editor.paragraph()/editor.blockquote()editor.orderedList()/editor.unorderedList()editor.link(url)/editor.unlink()editor.setFontSize(size)/editor.setFontFamily(family)editor.setColor(color)/editor.setBackgroundColor(color)editor.getHTML()/editor.getText()/editor.isEmpty()
Plugins
Scribe is built with a plugin-first architecture. Add only what you need and keep bundles lean.
- Built-in plugins live in src/plugins/
- External plugins can wrap common behaviors (toolbars, history, selection helpers)
Support
If you use Scribe in production, consider sharing feedback or contributing improvements.
License
BSD-3-Clause
