richtext-all
v1.0.0
Published
Universal, zero-dependency collaborative rich text & live editor engine for all JavaScript frameworks and platforms (React, Next.js, Vue 3, Angular, Svelte, Vanilla). Supports real-time collaboration with live cursors, presence avatars, revision audit his
Maintainers
Readme
✍️ RichText-All
The Universal, Zero-Dependency Collaborative Rich Text & Document Editor Engine
One unified API across React, Next.js, Vue 3, Angular, Svelte, and Vanilla HTML5.
🌐 Live Interactive Demo
Try RichText-All directly in your browser:
👉 Open Live Demo Playground
(Experience print-accurate A4 pagination, 3D card clustering, bilateral margin arrangement, version checkpoints with visual diffs, and 1-click DOCX import/export)
🚀 Why RichText-All?
| Feature | RichText-All 🌟 | TipTap | Quill | Slate | TinyMCE / CKEditor | | :--- | :---: | :---: | :---: | :---: | :---: | | Multi-Framework | React, Vue, Angular, Svelte, Vanilla | React & Vue only | Vanilla primarily | React only | Multi-framework | | Page Pagination | Print-accurate A4, Letter, Legal, Web | ❌ No | ❌ No | ❌ No | Paid Plugin | | Annotation Card Clustering | 3D Deck Stacking + Hover Fan-Out | ❌ No | ❌ No | ❌ No | ❌ No | | Bilateral Margins | Left, Right, or Auto Both Sides | ❌ No | ❌ No | ❌ No | ❌ No | | Track Changes & Suggestions | Built-in Additions & Deletions | Paid Cloud | ❌ No | ❌ No | Enterprise Paid | | Version History & Visual Diff | Word-by-word Side-by-side & Unified | Paid Cloud | ❌ No | ❌ No | Enterprise Paid | | Live Split Editor | Bidirectional Markdown <-> WYSIWYG | ❌ No | ❌ No | ❌ No | ❌ No | | Native Word DOCX Import | Built-in Zero-Dependency Parser | Plugins required | ❌ No | ❌ No | Paid Plugins | | Zero Runtime Dependencies | 0 Dependencies (~24 KB) | 20+ packages | 5+ packages | 10+ packages | Heavy (>150 KB) |
📦 Installation
npm install richtext-allOr via CDN:
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/richtext-all.css">
<script type="module" src="https://unpkg.com/[email protected]/dist/index.esm.js"></script>💡 Flagship Features
1. 📄 Print-Accurate Physical Page Layouts, In-Between Insertion & Page Reordering
- Switch between A4 (210×297mm), US Letter (8.5×11in), US Legal (8.5×14in), and Web (Infinite 100%).
- Insert Pages In-Between: Insert a new page anywhere between existing pages with one click via header buttons (
+ Add Page) oreditor.insertPageAt(index). All pages automatically renumber cleanly. - Interactive Page Reordering: Move pages up/down with 1-click header buttons (
↑ Up,↓ Down), drag-and-drop page sheets with the⠿handle, or programmatically reorder viaeditor.movePage(from, to)andeditor.reorderPages([3, 1, 2]). - Real-Time Continuous Typing Auto-Pagination: As text, images, or tables exceed page height budgets, overflow elements automatically advance to the next page sheet without splitting words awkwardly or breaking paragraph integrity.
- Page numbering pills (
Page 1,Page 2, ...) and insert/delete page breaks with one click.
2. 📚 Position-Based Card Clustering & 3D Deck Stacking
- Vertical Proximity Clustering: When multiple annotations (comments, suggestions, deletions) are created on the same line or within $50\text{px}$, they group into a single compact line cluster anchored to the text.
- Collapsed 3D Deck Stack: Displays the top card with a pill badge (
📚 N items on this line) and stacks subsequent cards with layered 3D depth and subtle vertical offsets. - Hover Fan-Out / Spread: Hovering the card cluster smoothly expands all cards vertically with dynamically accumulated heights and non-overlapping $12\text{px}$ spacing.
- Top-Layer Elevation: Hovering over marked phrases in the document body immediately pops that exact card to the top layer (
z-index: 300, elevated 3D shadow, and author's color border).
3. ⇋ Bilateral Margin Space Arrangement (left, right, both)
'right': All cards occupy the right margin space.'left': All cards occupy the left margin space.'both'(Automatic Bilateral): Activates both left and right margin spaces:- Single annotations on a line occupy their closest margin space.
- Two annotations on the same line automatically occupy opposite sides (one on Left, one on Right), giving each card full visibility without clustering!
- When line space on both margins is filled (3+ items), subsequent annotations form balanced card stacks on both sides.
4. ⚖️ Version History Checkpoints & Word-by-Word Visual Diff
- Save manual checkpoints and automated snapshots with word count and author stamps.
- Interactive Visual Diff Visualizer Modal:
- Compare any past checkpoint against another or the Live Active Document.
- Side-by-Side Split View with synchronized scrolling.
- Unified View showing deletions in red strike-through (
-Red) and additions in green underline (+Green). - One-click rollback to restore any previous document revision.
5. 💬 Threaded Comments & Collaborative Discussion
- Multi-User Replies: Any collaborator can post threaded replies directly inside gutter cards or via API.
- Resolve & Delete: Mark comments as resolved with one click (stored with
resolvedByandresolvedAtaudit metadata) or delete obsolete discussion threads. - Filterable Discussion: Query active or resolved threads at any time with
editor.getComments({ resolved: false }).
6. ✏️ Track Changes Suggestions & Reviewer Acceptance Workflow
- Suggesting Mode: Direct edits are transformed into clean visual suggestions (green additions, red strikethrough deletions).
- Reviewer Tracking: When suggestions are accepted or rejected, the system logs the reviewer's ID, name, color, and timestamp (
reviewedBy,reviewedAt). - Granular Filtering: Filter pending, accepted, or rejected suggestions via
editor.getSuggestions({ status: 'pending' }).
7. 📂 High-Performance Word (.docx) Import (1000+ Pages with Images & Links)
- Zero-Freeze Continuous Mode: Automatically detects large documents (>30 pages) and switches to an ultra-efficient continuous sheet with visual print-break dividers. Easily loads 1000+ page documents at smooth 60 FPS without DOM memory bloat.
- Embedded Images & Links: Built-in zero-dependency ZIP & XML engine extracts all embedded media (
word/media/*) into base64 images and resolves all hyperlinks (word/_rels/document.xml.rels). - Export clean
.docx,.md,.html,.json, and plain.txtfiles.
8. 👥 Collaborator Identity & User Switcher
- Assign each team member a distinct name and author color.
- Dropdown user switcher with custom color picker dialog (
+ User). - Metadata persists across all comments, replies, suggestions, and cursor badges.
9. 🎛️ Fully Configurable Toolbar: Defaults & Granular Show/Hide
- Customizable Default Values: Set defaults for every toolbar control on initialization or at runtime (
style,fontSize,lineHeight,color,highlight,layout,margin,mode,tableRows,tableCols). - Complete Toolbar Visibility: Toggle the entire ribbon with
editor.hideToolbar()/editor.showToolbar()or initialize withtoolbar: falseortoolbar: { visible: false }. - Granular Item Visibility: Show or hide specific buttons, dropdowns, or feature groups with
hiddenItems: ['upload', 'table'],show: { mode: false }, or whitelist withitems: ['style', 'bold', 'italic']. - Dynamic Runtime Controls: Freely call
editor.hideToolbarItem(key),editor.showToolbarItem(key),editor.toggleToolbarItem(key), oreditor.setToolbarDefaults(defaults). - Automatic Group & Divider Management: Dividers and empty groups cleanly auto-collapse when child items are hidden.
10. ⚡ Zero-Config Real-Time Multiplayer Collaboration
- Zero-Server Multi-Tab Sync (
BroadcastChannel): Open 2, 3, or 5 tabs or windows in your browser—all edits, typing tooltips, and live colored cursors sync instantly with zero configuration and zero backend needed. - Cross-Browser & Network Sync (
WebSocket): Seamlessly sync across different browsers (Chrome, Firefox, Edge, Safari) and different computers on your network by passingcollab: { serverUrl: 'ws://localhost:1234' }. - Built-in Zero-Dependency Relay Server: Launch the included WebSocket server in one command with
npm run collab(pure Node.js standard library, 0 external npm dependencies).
🛠️ Framework Integration
1. React / Next.js (App Router & Pages Router)
import React, { useRef } from 'react';
import { RichEditor } from 'richtext-all/react';
import 'richtext-all/css';
export default function DocumentEditor() {
const editorRef = useRef(null);
return (
<div style={{ height: '90vh', maxWidth: '1200px', margin: '0 auto' }}>
<RichEditor
ref={editorRef}
pageLayout="a4" // 'a4' | 'letter' | 'legal' | 'infinite'
gutterPosition="both" // 'right' | 'left' | 'both'
user={{
id: 'usr-1',
name: 'Sarah (Design Lead)',
color: '#ec4899'
}}
onSave={(data) => {
console.log('Document HTML:', data.html);
console.log('Markdown:', data.markdown);
}}
/>
</div>
);
}2. Vue 3 / Nuxt 3
<template>
<div class="editor-container">
<RichEditor
v-model="content"
page-layout="a4"
gutter-position="both"
:user="{ id: 'usr-2', name: 'Alex (Tech Lead)', color: '#059669' }"
@change="onContentChange"
/>
</div>
</template>
<script setup>
import { ref } from 'vue';
import { RichEditor } from 'richtext-all/vue';
import 'richtext-all/css';
const content = ref('<h1>Project Overview</h1><p>Collaborate in real time!</p>');
const onContentChange = (stats) => {
console.log('Word count:', stats.words);
};
</script>3. Angular (12+)
import { Component } from '@angular/core';
import { RichEditorComponent } from 'richtext-all/angular';
@Component({
selector: 'app-document-view',
standalone: true,
imports: [RichEditorComponent],
template: `
<rich-editor
[pageLayout]="'a4'"
[gutterPosition]="'both'"
(onSave)="handleSave($event)">
</rich-editor>
`
})
export class DocumentViewComponent {
handleSave(doc: any) {
console.log('Saved document HTML:', doc.html);
}
}4. Vanilla JavaScript / HTML5
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="node_modules/richtext-all/dist/richtext-all.css">
</head>
<body>
<div id="editor-mount"></div>
<script type="module">
import { RichEditor } from 'richtext-all';
const editor = new RichEditor('#editor-mount', {
pageLayout: 'a4',
gutterPosition: 'both',
user: { name: 'Veeresh', color: '#6366f1' }
});
// Programmatic Margin Space API
editor.setGutterPosition('left'); // Switch to left margin
editor.setGutterPosition('right'); // Switch to right margin
editor.setGutterPosition('both'); // Automatic bilateral margin distribution
// Checkpoints & Diff
editor.saveVersion('First Milestone Draft');
</script>
</body>
</html>📖 API Reference
Configuration Options
| Option | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| pageLayout | 'a4' \| 'letter' \| 'legal' \| 'infinite' | 'a4' | Document page format with auto-pagination. |
| gutterPosition | 'right' \| 'left' \| 'both' | 'right' | Annotation margin space placement mode. |
| toolbar | boolean \| object | true | Full toolbar configuration: { visible, defaults, show, hiddenItems, items }. |
| toolbarDefaults | object | {} | Shortcut for default values (style, fontSize, lineHeight, etc.). |
| user | { id, name, color } | Author | Active user credentials and highlight color. |
| users | Array<{ id, name, color }> | Default list | Pre-populated team collaborators. |
| collab | boolean \| object | true | Real-time collaboration: { roomId, serverUrl, user } (BroadcastChannel across tabs + WebSocket over network). |
| placeholder | string | 'Write something...' | Watermark text displayed on empty pages. |
| readOnly | boolean | false | Locks document editing. |
| autoFocus | boolean | false | Focuses the first page on load. |
Toolbar Customization & Default Values
import { RichEditor } from 'richtext-all';
const editor = new RichEditor('#editor', {
pageLayout: 'a4',
toolbar: {
visible: true, // Set false to start with toolbar completely hidden
defaults: {
style: 'p', // 'p' | 'h1'-'h6' | 'blockquote' | 'codeBlock'
fontSize: '16', // '12' | '14' | '16' | '18' | '20' | '24' | '32'
lineHeight: '1.6', // '1.0' | '1.2' | '1.4' | '1.5' | '1.6' | '2.0'
color: '#0f172a', // Default text color hex
highlight: '#facc15', // Default highlight swatch color hex
layout: 'a4', // 'a4' | 'letter' | 'legal' | 'infinite'
margin: 'right', // 'right' | 'left' | 'both'
mode: 'editing', // 'editing' | 'viewing' | 'suggesting' | 'comments'
tableRows: 3, // Default rows in table insertion modal
tableCols: 3 // Default columns in table insertion modal
},
// Hide specific buttons or feature groups on load:
hiddenItems: ['upload', 'table', 'mode'],
// Or selectively show/hide via map:
show: {
upload: false,
table: false
}
}
});⚡ Real-Time Collaboration Setup
1. Zero-Config Multi-Tab Sync (No server needed)
Open multiple browser tabs or windows—they automatically sync via BroadcastChannel:
const editor = new RichEditor('#editor', {
collab: {
roomId: 'project-proposal-room',
user: { id: 'usr-1', name: 'Alice', color: '#6366f1' }
}
});2. Cross-Browser & Multi-Device Sync (WebSocket)
To sync between different browsers (Chrome ↔ Firefox ↔ Edge) or different devices on your network:
- Start the included zero-dependency WebSocket relay server:
npm run collab
# Server listening on ws://localhost:1234- Point your editor to the server:
const editor = new RichEditor('#editor', {
collab: {
serverUrl: 'ws://localhost:1234',
roomId: 'team-design-room',
user: { id: 'usr-2', name: 'Bob', color: '#ec4899' }
}
});Supported Toolbar Item Keys & Aliases
| Item Key | Group / Control | Aliases |
| :--- | :--- | :--- |
| upload | Open DOCX document button | browse |
| history | Undo & Redo group | undoRedo |
| undo / redo | Individual undo/redo buttons | — |
| style | Paragraph, H1-H6, Quote dropdown | heading, headings |
| typography | Font size & Line spacing group | fonts |
| fontSize | Font size select dropdown | font |
| lineHeight | Line spacing select dropdown | lineSpacing, spacing |
| formatting | B, I, U, S, Tx buttons group | — |
| bold / italic / underline | Individual format buttons | — |
| strikeThrough | Strikethrough button | strikethrough |
| removeFormat | Clear formatting (Tx) button | clearFormatting, clearFormat, tx |
| colors | Text & highlight color group | — |
| color | Text color picker | textColor, pen |
| highlight | Highlight background swatch | bgColor, highlightColor, swatch |
| align | Alignment buttons group | alignment |
| list | Bulleted & Numbered list group | lists |
| insert | Link, Image, Table group | — |
| link / image / table | Individual insert controls | — |
| page | Add Page & Layout group | — |
| addPage / layout | Add Page button / Layout select | newPage, pageLayout |
| review | Comment, Margin, Save Version group | — |
| comment | Add Comment button | addComment, comments |
| margin | Margin space dropdown (Right/Left/Both) | gutter, gutterPos, gutterPosition |
| saveVersion | Save Version checkpoint button | versionHistory, saveVer, checkpoint |
| mode | Document Mode dropdown | documentMode |
| users | Active user switcher & +User button | user, collaborators |
Core Methods
| Method | Returns | Description |
| :--- | :--- | :--- |
| editor.showToolbar() | RichEditor | Shows the docked ribbon toolbar. |
| editor.hideToolbar() | RichEditor | Hides the docked ribbon toolbar. |
| editor.toggleToolbar(force?) | RichEditor | Toggles toolbar ribbon visibility. |
| editor.isToolbarVisible() | boolean | Returns true if toolbar is currently displayed. |
| editor.showToolbarItem(key) | RichEditor | Displays a specific toolbar item or group. |
| editor.hideToolbarItem(key) | RichEditor | Hides a specific toolbar item or group. |
| editor.toggleToolbarItem(key, force?) | RichEditor | Toggles visibility of a specific toolbar item. |
| editor.isToolbarItemVisible(key) | boolean | Returns whether the item is currently visible. |
| editor.setToolbarItemVisibility(key, visible) | RichEditor | Sets visibility of a single item or group. |
| editor.setToolbarItemsVisibility(map) | RichEditor | Batch sets visibility e.g. { upload: false, table: false }. |
| editor.setToolbarDefaults(defaults) | object | Sets and applies default values (fontSize, margin, etc.). |
| editor.getToolbarDefaults() | object | Returns current toolbar default values. |
| editor.setGutterPosition(pos) | string | Sets margin space ('left', 'right', or 'both'). |
| editor.getGutterPosition() | string | Returns current margin space. |
| editor.toggleGutterPosition() | string | Cycles margin: right ➔ left ➔ both ➔ right. |
| editor.setLayout(type) | void | Changes page layout ('a4', 'letter', 'legal', 'infinite'). |
| editor.addNewPage() | HTMLElement | Appends a new physical page sheet to the end. |
| editor.insertPageAt(pageNumber, html?) | HTMLElement | Inserts a new page sheet at the specified 1-based page position. |
| editor.insertPageAfter(pageNumber, html?) | HTMLElement | Inserts a new page sheet immediately after pageNumber. |
| editor.insertPageBefore(pageNumber, html?) | HTMLElement | Inserts a new page sheet immediately before pageNumber. |
| editor.removePage(pageNumber) | boolean | Removes a page sheet by its 1-based number. |
| editor.movePage(fromNumber, toNumber) | boolean | Moves a page from one position to another and updates DOM. |
| editor.movePageUp(pageNumber) | boolean | Swaps page with the preceding page sheet. |
| editor.movePageDown(pageNumber) | boolean | Swaps page with the following page sheet. |
| editor.reorderPages(newOrderArray) | boolean | Reorders all pages according to an array of page numbers (e.g. [3, 1, 2]). |
| editor.getPageCount() | number | Returns total number of physical pages. |
| editor.getPage(pageNumber) | HTMLElement \| null | Returns the page sheet DOM element. |
| editor.getPageHTML(pageNumber) | string | Returns HTML content of a specific page. |
| editor.setPageHTML(pageNumber, html) | boolean | Sets HTML content of a specific page sheet. |
| editor.getData() / editor.getDocumentContext() | object | Exports complete developer context bundle (content, comments, suggestions, versions, metadata, settings). |
| editor.setData(bundle) / editor.setDocumentContext(bundle) | boolean | Restores entire document context from exported JSON bundle. |
| editor.saveVersion(title, description?) | object | Creates a named version checkpoint with comments and layout state. |
| editor.getVersions() | Array<object> | Returns array of all saved version checkpoints. |
| editor.setVersions(versionsList) | Array<object> | Imports/sets a custom array of versions. |
| editor.getVersion(id) | object \| null | Retrieves a specific checkpoint by ID (or 'live'). |
| editor.deleteVersion(id) | object \| false | Removes a version checkpoint by ID. |
| editor.restoreVersion(id, opts?) | object \| null | Restores document HTML, comments, and settings to that version. |
| editor.compareVersions(idA, idB?) | object | Computes word-by-word diff with stats, leftHtml, rightHtml, unifiedHtml. |
| editor.getComparisonList() | Array<object> | Returns chronological timeline of versions with incremental diff stats. |
| editor.showVersionComparison(idA?, idB?) | void | Opens interactive visual side-by-side / unified diff visualizer modal. |
| editor.showVersionHistory() | void | Opens interactive version checkpoints modal. |
| editor.addComment(text) | object | Adds a comment anchored to the active text selection. |
| editor.replyComment(commentId, text, user?) | object \| null | Adds a threaded reply to an existing comment. |
| editor.deleteCommentReply(commentId, replyId) | object \| false | Removes an individual reply from a comment thread. |
| editor.resolveComment(commentId, resolvedBy?) | object \| null | Resolves a comment, removes document highlight, and logs reviewer audit. |
| editor.deleteComment(commentId) | object \| false | Permanently deletes a comment and unwraps highlighted text. |
| editor.clearAllAnnotations() | object | Permanently clears all comments & suggestions, unwraps DOM marks, and returns full audit data { deletedComments, deletedSuggestions, totalComments, totalSuggestions, timestamp }. |
| editor.clearCommentsAndSuggestions() | object | Alias for editor.clearAllAnnotations(). |
| editor.getComments(filter?) | Array<object> | Gets comments with optional filter: { resolved: true \| false }. |
| editor.setComments(list) | Array<object> | Batch sets all comments in the document. |
| editor.acceptSuggestion(id, reviewer?) | object \| null | Accepts a suggestion, applies DOM changes, and records reviewer metadata. |
| editor.rejectSuggestion(id, reviewer?) | object \| null | Rejects a suggestion, unwraps/restores text, and records reviewer metadata. |
| editor.getSuggestions(filter?) | Array<object> | Gets suggestions with optional filter: { status: 'pending' \| 'accepted' \| 'rejected' }. |
| editor.setSuggestions(list) | Array<object> | Batch sets all tracked suggestions. |
| editor.exportContextJSON(filename?) | void | Downloads complete developer document context as .json. |
| editor.addUser(name, color) | object | Registers and selects a new collaborator. |
| editor.setUser(userOrId) | object | Switches active author identity. |
| editor.importDocument(file, options?) | Promise<string \| null> | Imports .docx, .doc, .md, .html, .txt, or .json. Prompts confirmation dialog if comments/suggestions exist before clearing them. |
| editor.browseAndOpen(options?) | Promise<string \| null> | Prompts file picker with overwrite confirmation protection. |
| editor.getHTML() | string | Returns clean document HTML. |
| editor.getMarkdown() | string | Converts document to Markdown. |
| editor.getJSON() | object | Returns structured JSON AST. |
| editor.getStats() | object | Returns word count, character count, and reading time. |
📦 Developer-Friendly Document Context & Workflow API
// 1. Export Complete Document Context Bundle (Ready for Database / REST API)
const bundle = editor.getData();
console.log(bundle);
/*
{
schemaVersion: '1.0.0',
metadata: { title: 'Q4 Product Spec', author: 'Veeresh Poojari', stats: { words: 420, chars: 2800 } },
settings: { pageLayout: 'a4', gutterPosition: 'both', mode: 'editing' },
content: { html: '...', markdown: '...', text: '...', json: { ... } },
comments: [
{
id: 'c-101',
text: 'Please clarify this milestone',
author: 'Veeresh',
resolved: false,
replies: [
{ id: 'rep-1', text: 'Updated with technical details', author: 'Alex', timestamp: '14:20' }
]
}
],
suggestions: [
{
id: 's-202',
type: 'add',
text: 'real-time multi-tab',
author: 'Alex',
status: 'accepted',
reviewedBy: { id: 'usr-lead', name: 'Tech Lead', color: '#16a34a' },
reviewedAt: '2026-10-08T12:00:00.000Z'
}
],
versions: [ ... ],
comparisonList: [ ... ],
users: [ ... ]
}
*/
// 2. Restore or Load Into Any Editor Instance
editor.setData(bundle);
// 3. Threaded Comments & Discussion API
const comment = editor.addComment('Review paragraph 3');
editor.replyComment(comment.id, 'Looks good to me!', { name: 'Sarah', color: '#ec4899' });
editor.resolveComment(comment.id, 'Veeresh (Lead)'); // Resolves and unhighlights text
const activeComments = editor.getComments({ resolved: false }); // Query unresolved only
// 4. Track Changes Suggestions & Reviewer Acceptance API
editor.setMode('suggesting'); // Swaps to suggesting mode
// When reviewer approves or rejects:
editor.acceptSuggestion('s-202', { id: 'usr-admin', name: 'Lead Reviewer', color: '#10b981' });
editor.rejectSuggestion('s-203', { id: 'usr-admin', name: 'Lead Reviewer', color: '#ef4444' });
const pendingSuggestions = editor.getSuggestions({ status: 'pending' });
// 5. Save Named Version Checkpoints & Visual Diffs
const v1 = editor.saveVersion('v1.0 Baseline', 'Initial draft before peer review');
const v2 = editor.saveVersion('v1.1 Review Edits', 'Addressed comments from tech lead');
const comparison = editor.compareVersions(v1.id, v2.id); // Or compare against 'live'
console.log(comparison.stats); // { additions: 14, deletions: 3, unchanged: 180, totalChanges: 17 }
console.log(comparison.leftHtml); // Baseline with deletions highlighted in red
console.log(comparison.rightHtml); // Target with additions highlighted in green
console.log(comparison.unifiedHtml); // Combined inline diff
// 6. Opening Documents with Overwrite Confirmation & Database Sync
// When opening a DOCX with active comments/suggestions, a styled modal warns the user
// that all existing annotations will be permanently deleted.
// If accepted, it deletes them and loads the new document; if cancelled, the current document is preserved.
// Custom confirmation hook or bypass:
await editor.importDocument(file, {
confirmOnOverwrite: true, // Set false to skip dialog if desired
onConfirmOverwrite: async ({ file, commentsCount, suggestionsCount }) => {
// Custom UI dialog (e.g. SweetAlert, AntD, Shadcn)
return window.confirm(`Permanently remove ${commentsCount} comments and ${suggestionsCount} suggestions?`);
}
});
// Programmatic bulk delete & database synchronization:
const audit = editor.clearAllAnnotations();
console.log('Audit Report:', audit);
/*
{
deletedComments: [ { id: 'c-1', text: '...', ... } ],
deletedSuggestions: [ { id: 's-1', ... } ],
totalComments: 1,
totalSuggestions: 1,
timestamp: "2026-10-08T14:30:00.000Z"
}
*/
// Sync deletions with your backend database:
if (audit.totalComments > 0) {
await myDatabase.comments.deleteMany({ id: { $in: audit.deletedComments.map(c => c.id) } });
}
if (audit.totalSuggestions > 0) {
await myDatabase.suggestions.deleteMany({ id: { $in: audit.deletedSuggestions.map(s => s.id) } });
}
// Or listen to the documentImported event:
editor.on('documentImported', async ({ file, html, deletedAnnotations }) => {
if (deletedAnnotations && (deletedAnnotations.totalComments > 0 || deletedAnnotations.totalSuggestions > 0)) {
await syncDeletedAnnotationsToBackend(deletedAnnotations);
}
});
// 7. Page Insertion & Reordering API
// Insert a new page between Page 1 and Page 2:
editor.insertPageAt(2, '<h2>Chapter 2: Architecture Deep Dive</h2><p>Overview...</p>');
// Or insert relative to existing pages:
editor.insertPageAfter(2); // Inserts right after Page 2 (becomes Page 3)
editor.insertPageBefore(1); // Inserts brand new cover page (becomes Page 1)
// Reorder pages:
editor.movePage(3, 1); // Moves Page 3 to the very front (Page 1)
editor.movePageUp(2); // Swaps Page 2 with Page 1
editor.movePageDown(2); // Swaps Page 2 with Page 3
// Batch reorder all pages to a new sequence:
editor.reorderPages([3, 1, 2]); // Page 3 becomes Page 1, Page 1 becomes Page 2, Page 2 becomes Page 3
console.log('Total pages:', editor.getPageCount());🧪 Testing
Run the zero-dependency test suite covering security, pagination, card clustering, bilateral arrangement, and visual diffs:
npm test📄 License
MIT © Veeresh Poojari.
