npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@kanaka-prabhath/html-editor

v1.1.15

Published

A React-based WYSIWYG continuous HTML editor with rich text formatting and automatic page break insertion

Readme

@kanaka-prabhath/html-editor

npm version License: MIT GitHub Issues GitHub Stars

A React-based WYSIWYG HTML editor with automatic page reflow, rich text formatting, and multi-page document management. Perfect for creating documents, reports, and rich content editors.

HTML Editor Screenshot

✨ Features

  • WYSIWYG Editing: Real-time HTML content editing with rich text formatting
  • Automatic Page Reflow: Content automatically flows across pages with intelligent page break insertion
  • Multi-Page Management: Navigate, add, delete, and manage pages seamlessly
  • Rich Text Formatting: Bold, italic, underline, strikethrough, alignment, fonts, and font sizes
  • Page Size Support: A4, Letter, and Legal page formats with programmatic configuration
  • Page Margin Control: Customizable page margins with preset and custom options
  • Advanced Content Selection: Retrieve selected HTML content for advanced editing workflows
  • Zoom Controls: 50%-200% zoom with keyboard shortcuts and programmatic control
  • Table Support: Advanced table creation, resizing, and manipulation with column/row resizing
  • Image Manipulation: Image upload, insertion, and resize controls with aspect ratio preservation
  • Indentation System: Tab-based paragraph indentation with toolbar buttons and keyboard shortcuts
  • Keyboard Shortcuts: Comprehensive keyboard shortcuts for formatting, navigation, and operations
  • Content Normalization: Automatic HTML content normalization for tables, lists, images, headings, and complex structures
  • Page Break Management: Visual page break removal with automatic content reflow
  • Customizable UI: Show/hide sidebar, toolbar, and page manager components
  • Performance Optimized: Efficient reflow algorithms and debounced operations
  • TypeScript Ready: Full type definitions included
  • Responsive Design: Works across desktop and mobile devices
  • Accessibility: Keyboard navigation, focus indicators, and ARIA attributes
  • Image Storage: IndexedDB-based image storage for offline functionality
  • Undo/Redo Support: Browser-native undo/redo functionality
  • Content Export: HTML and plain text content extraction methods
  • Async Content Methods: getHTMLContent(), setContent(), and insertContent() are async for automatic image conversion

📦 Installation

# Install the editor library
npm install @kanaka-prabhath/html-editor

# Install peer dependencies (if not already installed)
npm install react react-dom

🚀 Quick Start

import React from 'react';
import { HtmlEditor, DocumentProvider } from '@kanaka-prabhath/html-editor';
import '@kanaka-prabhath/html-editor/styles';

function App() {
  return (
    <DocumentProvider>
      <HtmlEditor />
    </DocumentProvider>
  );
}

export default App;

🎯 Advanced Usage

Zoom Controls

import { useDocumentState, useDocumentActions } from '@kanaka-prabhath/html-editor';

function ZoomControls() {
  const { zoomLevel } = useDocumentState();
  const { setZoomLevel, zoomIn, zoomOut, resetZoom } = useDocumentActions();

  return (
    <div>
      <p>Current Zoom: {zoomLevel}%</p>
      <button onClick={() => setZoomLevel(125)}>Set 125%</button>
      <button onClick={zoomIn}>Zoom In</button>
      <button onClick={zoomOut}>Zoom Out</button>
      <button onClick={resetZoom}>Reset Zoom</button>
    </div>
  );
}

Table Manipulation

import { createTableResizeOverlay, applyTableDimensions } from '@kanaka-prabhath/html-editor';

function TableEditor() {
  const handleTableResize = (tableElement, newDimensions) => {
    applyTableDimensions(tableElement, newDimensions);
  };

  return (
    <div>
      {/* Tables in the editor automatically get resize handles */}
      {/* Use the utilities for programmatic table manipulation */}
    </div>
  );
}

Indentation System

function IndentationExample() {
  const editorRef = useRef(null);

  const insertIndentedContent = () => {
    // Insert content with indentation
    editorRef.current.insertContent('<p data-indent-level="2">Indented paragraph</p>');
  };

  return (
    <div>
      <DocumentProvider>
        <HtmlEditor ref={editorRef} />
      </DocumentProvider>
      <button onClick={insertIndentedContent}>Insert Indented Content</button>
    </div>
  );
}

Keyboard Shortcuts

The editor supports comprehensive keyboard shortcuts:

Formatting:

  • Ctrl+B - Bold
  • Ctrl+I - Italic
  • Ctrl+U - Underline
  • Ctrl+A then formatting - Apply to selection

Navigation:

  • Tab - Increase indent (at cursor or selection)
  • Shift+Tab - Decrease indent (selection only)
  • Ctrl+A - Select all

Zoom:

  • Ctrl++ - Zoom in
  • Ctrl+- - Zoom out
  • Ctrl+0 - Reset zoom

Async Content Methods:

The getHTMLContent(), setContent(), and insertContent() methods are now asynchronous to handle automatic image conversion between blob URLs and base64 data URLs. This ensures optimal performance by storing images as blob URLs during editing while providing base64-encoded images for export.

Content Change Callbacks:

The editor provides two content change callbacks with different performance characteristics:

  • onChange: Called on every content change with raw HTML (blob URLs). Use for real-time updates.
  • onContentFinalized: Called after 2 seconds of inactivity with base64-converted HTML. Use for saving/exporting.
function AutoSaveEditor() {
  const handleContentChange = (html) => {
    // Real-time updates with blob URLs (fast)
    console.log('Content changed:', html.length, 'characters');
  };
  
  const handleContentFinalized = (html) => {
    // Finalized content with base64 images (for saving)
    localStorage.setItem('draft', html);
  };
  
  return (
    <HtmlEditor 
      onChange={handleContentChange}
      onContentFinalized={handleContentFinalized}
    />
  );
}

Key Benefits:

  • Automatic Conversion: Images are automatically converted between formats
  • Performance Optimized: Blob URLs for fast editing, base64 for export
  • IndexedDB Storage: Images stored in IndexedDB for persistence
  • Error Handling: Graceful handling of conversion failures

Usage Examples:

// Export content with base64 images
const exportContent = async () => {
  const htmlWithBase64 = await editorRef.current.getHTMLContent();
  // htmlWithBase64 contains base64-encoded images ready for export
  return htmlWithBase64;
};

// Import content with base64 images
const importContent = async (htmlWithBase64) => {
  await editorRef.current.setContent(htmlWithBase64);
  // Images are automatically converted to blob URLs and stored in IndexedDB
};

// Insert content at cursor with base64 images
const insertAtCursor = async (htmlWithBase64) => {
  await editorRef.current.insertContent(htmlWithBase64);
  // Images are automatically converted and stored
};

🔧 API Reference

HtmlEditor

The main editor component with ref access to content methods.

Props:

  • pageManagerComponent?: ReactNode - Custom page manager component
  • onNavigatePage?: (pageIndex: number) => void - Page navigation callback
  • onAddPage?: () => void - Page addition callback
  • onDeletePage?: (pageIndex: number) => void - Page deletion callback
  • onPageSizeChange?: (size: 'A4' | 'Letter' | 'Legal') => void - Page size change callback
  • onPageMarginsChange?: (margins: PageMarginPreset | CustomMargins) => void - Page margins change callback
  • onChange?: (htmlContent: string) => void - Content change callback (real-time with blob URLs)
  • onContentFinalized?: (htmlContent: string) => void - Finalized content callback (debounced with base64 images)
  • showSidebar?: boolean - Show/hide sidebar (default: true)
  • showToolbar?: boolean - Show/hide toolbar (default: true)
  • showPageManager?: boolean - Show/hide page manager (default: true)

Ref Methods:

  • getHTMLContent(): Promise<string> - Returns current HTML content with blob URLs converted to base64
  • getSelectedHTMLContent(): string - Returns selected HTML content (supports images and tables)
  • getPlainText(): string - Returns plain text content
  • setContent(html: string): Promise<void> - Set editor content programmatically, converting base64 images to blobs
  • setPageSize(size: 'A4' | 'Letter' | 'Legal'): void - Set page size programmatically
  • setPageMargins(margins: PageMarginPreset | CustomMargins): void - Set page margins programmatically
  • insertContent(html: string): Promise<void> - Insert content at cursor position, converting base64 images to blobs

DocumentProvider

Context provider for document state management.

<DocumentProvider initialState={{ title: "Document", pageSize: "A4" }}>
  <HtmlEditor />
</DocumentProvider>

Context Hooks

useDocumentState() - Access current document state

  • Returns: { id, title, createdAt, updatedAt, pages, activePage, pageSize, zoomLevel, continuousContent, pageBoundaries, ... }

useDocumentActions() - Access document state actions

  • updateContinuousContent(html: string) - Update continuous content
  • setActivePage(index: number) - Set active page
  • addPage() - Add new page
  • deletePage(index: number) - Delete page at index
  • setPageSize(size: string) - Set page size
  • setZoomLevel(level: number) - Set zoom level (50-200)
  • zoomIn() - Increase zoom by 5%
  • zoomOut() - Decrease zoom by 5%
  • resetZoom() - Reset zoom to 100%

Formatting Hooks

useFormatting() - Text formatting state and commands

  • Returns: { currentFormat, formatText, applyFormatting }

useContinuousReflow(pageSize, editorRef, zoomLevel?) - Automatic content reflow engine

  • Returns: { checkAndUpdateBoundaries, triggerAutoReflow, scrollToPage, getCurrentPage, positionCursorAtPage, removePageAndContent }

Image Storage Utilities

  • saveImage(file: File): Promise<string> - Save image to IndexedDB, returns storage key
  • getImage(key: string): Promise<string> - Retrieve image data URL by key
  • deleteImage(key: string): Promise<void> - Delete image by key
  • clearImages(): Promise<void> - Clear all stored images
  • getAllImageKeys(): Promise<string[]> - Get all stored image keys

Page and Font Utilities

  • PAGE_SIZES - Object with A4, Letter, Legal dimensions
  • getPageDimensions(size: string): {width: number, height: number} - Get page dimensions in pixels
  • isValidPageSize(size: string): boolean - Validate page size
  • getAvailablePageSizes(): string[] - Get available page sizes
  • FONT_SIZE_MAP - Font size mappings
  • pointsToPixels(points: number): number - Convert points to pixels
  • pixelsToPoints(pixels: number): number - Convert pixels to points
  • isValidFontSize(size: number): number - Validate and return valid font size

Table Manipulation Utilities

  • isResizableTable(element: HTMLElement): boolean - Check if element is a resizable table
  • getTableStructure(table: HTMLTableElement) - Get table structure info
  • calculateTableResizeDimensions(params): object - Calculate resize dimensions
  • applyTableDimensions(table: HTMLTableElement, dimensions, type?) - Apply dimensions to table
  • createTableResizeOverlay(table: HTMLTableElement) - Create resize overlay
  • updateTableResizeOverlay(overlay: HTMLElement, table: HTMLTableElement) - Update overlay

Image Manipulation Utilities

  • isResizableImage(element: HTMLElement): boolean - Check if element is a resizable image
  • getImageDimensions(img: HTMLImageElement) - Get image dimensions
  • applyImageDimensions(img: HTMLImageElement, dimensions) - Apply dimensions to image
  • createResizeOverlay(img: HTMLImageElement) - Create image resize overlay
  • updateResizeOverlay(overlay: HTMLElement, img: HTMLImageElement) - Update overlay
  • removeResizeOverlay() - Remove resize overlay

Types

PageMarginPreset:

  • 'NORMAL' - 1" margins all sides
  • 'NARROW' - 0.5" margins all sides
  • 'MODERATE' - 1" top/bottom, 0.75" left/right
  • 'WIDE' - 1" top/bottom, 2" left/right
  • 'OFFICE_2003' - 1" top/bottom, 1.25" left/right

CustomMargins:

{
  top: number,    // Top margin in inches
  bottom: number, // Bottom margin in inches
  left: number,   // Left margin in inches
  right: number   // Right margin in inches
}

📖 Documentation

For complete documentation, check out our Wiki which includes:

🎨 Styling

Import default styles:

import '@kanaka-prabhath/html-editor/styles';

Or use your own CSS:

.multi-page-editor {
  border: 1px solid #e0e0e0;
  border-radius: 8px;
}

.editor-toolbar {
  background: #f8f9fa;
  border-bottom: 1px solid #e0e0e0;
}

🔍 Examples

Custom Page Manager

import { useDocumentActions, useDocumentState } from '@kanaka-prabhath/html-editor';

function CustomPageManager() {
  const { pages, activePage } = useDocumentState();
  const { setActivePage, addPage } = useDocumentActions();

  return (
    <div className="custom-pager">
      <button onClick={addPage}>+ Add Page</button>
      {pages.map((_, index) => (
        <button
          key={index}
          onClick={() => setActivePage(index)}
          className={index === activePage ? 'active' : ''}
        >
          Page {index + 1}
        </button>
      ))}
    </div>
  );
}

// Usage
<HtmlEditor pageManagerComponent={<CustomPageManager />} />

Programmatic Content Control

function TemplateLoader() {
  const editorRef = useRef(null);

  const loadTemplate = async (template) => {
    await editorRef.current.setContent(template);
  };

  const insertSignature = async () => {
    await editorRef.current.insertContent('<p><em>-- Document Signature</em></p>');
  };

  return (
    <div>
      <DocumentProvider>
        <HtmlEditor ref={editorRef} />
      </DocumentProvider>
      <button onClick={() => loadTemplate('<h1>Template</h1><p>Content</p>')}>
        Load Template
      </button>
      <button onClick={insertSignature}>
        Insert Signature
      </button>
    </div>
  );
}

🧪 Testing

The library includes a comprehensive test suite covering unit tests, integration tests, and end-to-end tests:

Test Categories

Unit Tests (tests/unit/):

  • Component exports and library structure
  • Document context contract and state management
  • Hook functionality (useContinuousReflow, useFormatting)
  • Utility functions (table resize, image handling, font utilities)
  • Page size and margin calculations
  • Content normalization and validation

Integration Tests (tests/integration/):

  • Page size dimensions and boundaries
  • Zoom controls and keyboard shortcuts
  • Cross-component interactions

End-to-End Tests (tests/e2e/):

  • Core text editing workflows
  • Image upload and manipulation
  • Page content management
  • Table creation and resizing
  • Indentation system (Tab/Shift+Tab)
  • UI specifications and responsive design
  • Keyboard shortcuts and accessibility

Running Tests

# Run all tests (unit + integration)
npm test

# Run end-to-end tests
npm run test:e2e

# Run E2E tests with UI
npm run test:e2e:ui

# Run E2E tests in debug mode
npm run test:e2e:debug

# Run tests with coverage
npm run test:coverage

Test Coverage

The test suite covers:

  • ✅ WYSIWYG editing functionality
  • ✅ Automatic page reflow and boundary calculations
  • ✅ Multi-page document management
  • ✅ Rich text formatting (bold, italic, underline, etc.)
  • ✅ Page size and margin controls
  • ✅ Zoom functionality (50%-200%)
  • ✅ Table creation, resizing, and manipulation
  • ✅ Image upload, storage, and resizing
  • ✅ Indentation system with Tab/Shift+Tab
  • ✅ Keyboard shortcuts
  • ✅ Content selection and manipulation
  • ✅ Responsive design and accessibility
  • ✅ Performance and edge cases

🤝 Contributing

We welcome contributions! Please see our Contributing Guide for details.

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests
  5. Submit a pull request

🐛 Reporting Issues

Found a bug? Please create an issue with:

  • Steps to reproduce
  • Expected vs actual behavior
  • Browser and environment information

💡 Feature Requests

Have an idea for improvement? Suggest a feature with:

  • Use case description
  • Proposed implementation
  • Value it would provide

📄 License

MIT License - see LICENSE file for details.

🔗 Links

  • GitHub: https://github.com/KanakaPrabhath/htmleditor
  • npm: https://www.npmjs.com/package/@kanaka-prabhath/html-editor
  • Issues: https://github.com/KanakaPrabhath/htmleditor/issues
  • Discussions: https://github.com/KanakaPrabhath/htmleditor/discussions

📋 Changelog

See CHANGELOG.md for a detailed list of changes.


Made with ❤️ by Kanaka Prabhath

If you find this library useful, please consider giving it a star on GitHub! ⭐