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

@malaya_jeeva/rich-text-editor

v1.0.13

Published

Custom React Rich Text Editor

Readme

📝 @malaya_jeeva/rich-text-editor

A lightweight, fully-featured Rich Text Editor (WYSIWYG) built from scratch with React + TypeScript. No heavy dependencies — just React.


🚀 Installation

npm install @malaya_jeeva/rich-text-editor

📦 Usage

Basic Example

'use client' // required for Next.js (App Router)

import React, { useState } from 'react'
import RichTextEditor from '@malaya_jeeva/rich-text-editor'

export default function Page() {
  const [value, setValue] = useState('')

  return (
    <RichTextEditor
      value={value}
      onChange={setValue}
      placeholder="Write something..."
      height={400}
      theme="light"
    />
  )
}

Uncontrolled (no props needed)

import RichTextEditor from '@malaya_jeeva/rich-text-editor'

export default function Page() {
  return <RichTextEditor />
}

⚙️ Props

| Prop | Type | Required | Default | Description | | ------------- | ----------------------------- | -------- | -------------------- | --------------------------------------------------------------------------- | | value | string | No | — | Initial HTML content (read on first mount only) | | onChange | (value: string) => void | No | — | Fires with full innerHTML on every change | | toolbar | ToolbarItem[] | No | all items | Controls which toolbar buttons are shown. If omitted, all buttons are shown | | placeholder | string | No | "Start typing..." | Placeholder text shown when the editor is empty | | height | number \| string | No | auto (max 350px) | Editor content area height — 500, "400px", "60vh" etc. | | theme | "light" \| "dark" \| "auto" | No | "auto" | Color theme. "auto" follows the OS prefers-color-scheme setting |

Type export

import type { RichTextEditorProps, ToolbarItem } from '@malaya_jeeva/rich-text-editor'

📐 Height

Control the height of the editor content area via the height prop. Accepts a number (pixels) or any valid CSS string.

<RichTextEditor height={500} />         // 500px fixed
<RichTextEditor height="60vh" />        // viewport-relative
<RichTextEditor height="400px" />       // explicit px string
<RichTextEditor />                      // default — grows with content, caps at 350px

💬 Placeholder

Set the placeholder text shown when the editor is empty.

<RichTextEditor placeholder="Write something..." />
// omit it — defaults to "Start typing..."

🌗 Theme

Three options: "light", "dark", or "auto" (default).

<RichTextEditor theme="light" />   // always light
<RichTextEditor theme="dark" />    // always dark
<RichTextEditor />                 // auto — follows OS prefers-color-scheme

When theme="auto" (or the prop is omitted) the editor automatically switches between light and dark based on the user's OS setting — no extra code needed.


🛠️ Toolbar Customization

Pass a toolbar array to control exactly which buttons appear. If the prop is omitted, all buttons are shown — fully backward compatible.

All available ToolbarItem keys

| Key | Button | Description | | --- | ------ | ----------- | | bold | B | Bold text | | italic | I | Italic text | | underline | U | Underline text | | color | A̲ | Text color picker (palette + HSV wheel + remove) | | blockFormat | Paragraph ▾ | Block format dropdown (Paragraph, H1, H2, H3) | | alignLeft | ≡ | Align text left | | alignCenter | ≡ | Align text center | | alignRight | ≡ | Align text right | | alignJustify | ≡ | Justify text | | bulletList | • | Unordered / bullet list | | numberedList | 1. | Ordered / numbered list | | indent | → | Increase indent (or go deeper in list) | | outdent | ← | Decrease indent (or go back up in list) | | link | 🔗 | Insert / edit hyperlink | | codeBlock | </> | Wrap selection in <pre><code> | | image | 🖼 | Insert image (upload, URL, or drop) | | table | ⊞ | Insert table (grid picker up to 8×8) | | html | HTML | Toggle between Visual and HTML source view | | copyHtml | ⎘ | Copy current HTML to clipboard |

Note: Separators between groups are rendered automatically — they appear only when buttons exist on both sides, so you never get a leading, trailing, or double separator regardless of your selection.


✨ Features

Text Formatting

  • Bold, Italic, Underline
  • 🎨 Text color picker — palette + custom HSV color wheel + remove color
  • 🔠 Block formats — Paragraph, Heading 1 / 2 / 3 (dropdown)
  • ↔️ Text alignment — Left, Center, Right, Justify

Lists

  • 📌 Bullet & Numbered lists with full multilevel nesting
  • Indent/outdent via toolbar or Tab / Shift+Tab
  • Nesting style: 1. → a. → i. for ordered, • → ◦ → ▪ for unordered

Links

  • 🔗 Insert link — floating inline bar appears near the selection
  • Edit link — click inside any link to see URL with Edit / Unlink buttons
  • Unlink — removes <a> tag while keeping the text

Images

  • 🖼️ Insert via upload — drag & drop onto the zone or click to browse
  • 🌐 Insert via URL — paste any image URL with live preview
  • 📥 Drop into editor — drag an image file directly onto the content
  • Click to edit — selecting an image opens a full control panel:
    • Style tab — Display (Block / Inline), Alignment (Left / Center / Right), Width presets (25% / 50% / 75% / 100% / Original), manual width input, Alt text
    • Caption tab — wraps image in <figure>/<figcaption>, editable caption text
    • Link tab — wrap image in <a> with Apply / Remove
  • 🔲 Drag-to-resize — 8 handles (corners preserve aspect ratio, edges resize freely)

Tables

  • 📊 Insert table — grid picker up to 8×8, first row auto-set as <th>
  • Floating context toolbar — appears near the active cell:
    • Add row above / below, Delete row
    • Add column left / right, Delete column
    • Delete entire table
  • Cell merge — drag or Shift+click to select a range → Merge button
  • Cell split — splits merged cells back to individual cells
  • Tab navigationTab / Shift+Tab to move between cells

Code

  • 💻 Code block — wraps selection in <pre><code>
  • 🔄 HTML / Visual toggle — switch between WYSIWYG and raw HTML source
  • Auto-prettify — HTML view auto-indents on switch
  • 📋 Copy HTML — copies current HTML to clipboard

General

  • ⌨️ Keyboard shortcuts — Ctrl+B, Ctrl+I, Ctrl+U
  • 📊 Live word count
  • 🌙 Dark mode support — automatic via prefers-color-scheme
  • 🏗️ Library-safe TSX — uses ReactElement returns, no global JSX namespace

🧠 Keyboard Shortcuts

| Shortcut | Action | | -------- | ------ | | Ctrl + B | Bold | | Ctrl + I | Italic | | Ctrl + U | Underline | | Tab | Indent list item / move to next table cell | | Shift + Tab | Outdent list item / move to previous table cell | | Enter (link bar) | Apply link | | Escape (link bar) | Dismiss link bar |


🖼️ Image Editor — Detail

Click any inserted image to open the image control panel.

Style tab

| Control | Options | | ------- | ------- | | Display | Block (full row) · Inline (flows with text) | | Alignment | Left · Center · Right | | Width | 25% · 50% · 75% · 100% · Original size · Custom (e.g. 300px) | | Alt text | Free text input | | Delete | Removes the image from the editor |

Caption tab

Wraps the image in <figure> + <figcaption>. The caption always renders below the image regardless of float alignment.

Link tab

Wraps the image in an <a> tag. Existing link can be edited or removed.

Drag resize

Drag any of the 8 blue handles around the selected image:

  • Corner handles — resize while preserving aspect ratio
  • Edge handles — resize width or height freely

📊 Table Guide

Inserting

  1. Click the table grid icon in the toolbar
  2. Hover to select rows × columns (up to 8×8)
  3. Click to insert — first row is automatically <th>

Cell merge

  • Drag across cells, or Shift+click a second cell to select a rectangle
  • Selected cells highlight in blue → click Merge in the floating toolbar

Cell split

Click inside a merged cell → Split button appears in the floating toolbar.


🎨 Color Picker

  • Palette — 34 preset colors in a compact grid
  • Black — one-click reset to automatic color
  • Remove — strips color from the selection
  • Custom — opens a full HSV color wheel with:
    • Saturation/brightness canvas (drag to pick exact shade)
    • Hue slider (full 360° spectrum)
    • Hex input field
    • Live preview swatch
    • Apply button

💡 Output Format

onChange returns standard HTML. Example:

<h2>Getting started</h2>
<p>This is a <strong>rich text</strong> editor.</p>
<ul>
  <li>Item one</li>
  <li>Item two
    <ul><li>Nested item</li></ul>
  </li>
</ul>
<figure style="margin:0.8em 0;display:block;overflow:hidden;">
  <img src="..." alt="diagram" style="max-width:100%;width:50%;" />
  <figcaption style="text-align:center;clear:both;">Figure 1</figcaption>
</figure>
<table>
  <tr><th>Name</th><th>Role</th></tr>
  <tr><td>Alice</td><td>Engineer</td></tr>
</table>

⚠️ Sanitization

The editor does not sanitize output. Before persisting to a database or rendering via dangerouslySetInnerHTML, run through a sanitizer:

npm install dompurify
npm install -D @types/dompurify
import DOMPurify from 'dompurify'

const clean = DOMPurify.sanitize(html)

🌐 Browser Support

| Browser | Support | | ------- | ------- | | Chrome 90+ | ✅ | | Firefox 90+ | ✅ | | Safari 15+ | ✅ | | Edge 90+ | ✅ |


🎯 Notes

  • Controlled component → always pass value and onChange together (or omit both)
  • Works with React 18+ and 19+
  • Compatible with Next.js (use 'use client')
  • Written in TypeScript — all props and internal types are exported

🔄 Local Development

# In the library folder
npm run build
npm link

# In your app
npm link @malaya_jeeva/rich-text-editor

👨‍💻 Author

Malaya Ranjan Jena


📄 License

ISC