← All @molecule/* packages · App templates

@molecule/app-rich-text

Feature · rich-text · App (browser) · v1.0.2 · Apache-2.0

Rich text editing and formatting

npm install @molecule/app-rich-text

npm · Source on GitHub

How it works

@molecule/app-rich-text is a ready-made rich-text feature for the app (browser) side. It composes the core interfaces it needs, so it works with whichever providers your app has bonded.

import { createEditor, htmlToValue, setProvider } from '@molecule/app-rich-text'
import type { TextChangeData } from '@molecule/app-rich-text'
import { provider as quillProvider } from '@molecule/app-rich-text-quill'

// Wire the provider once at app startup
setProvider(quillProvider)

// Create an editor instance attached to a DOM container
const container = document.getElementById('editor')!
const editor = createEditor({ container, placeholder: 'Start typing…', toolbar: 'standard' })

editor.on<TextChangeData>('text-change', ({ value }) => console.log(value.text))

// Convert existing HTML into the editor
editor.setValue(htmlToValue('<p>Hello <strong>world</strong></p>'))

Providers (1): @molecule/app-rich-text-quill

Works with: @molecule/app-bond

Reference

Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit src/index.ts JSDoc, not this file.

Rich text editor interface for molecule.dev.

Provides a unified API for rich text editing that can be backed by different editor implementations. Wire a provider with setProvider(); @molecule/app-rich-text-quill is the shipped production bond.

Quick Start

import { createEditor, htmlToValue, setProvider } from '@molecule/app-rich-text'
import type { TextChangeData } from '@molecule/app-rich-text'
import { provider as quillProvider } from '@molecule/app-rich-text-quill'

// Wire the provider once at app startup
setProvider(quillProvider)

// Create an editor instance attached to a DOM container
const container = document.getElementById('editor')!
const editor = createEditor({ container, placeholder: 'Start typing…', toolbar: 'standard' })

editor.on<TextChangeData>('text-change', ({ value }) => console.log(value.text))

// Convert existing HTML into the editor
editor.setValue(htmlToValue('<p>Hello <strong>world</strong></p>'))

Type

feature

Installation

npm install @molecule/app-rich-text @molecule/app-bond dompurify

API

Interfaces

EditorOptions

Configuration options for creating a new rich text editor instance.

interface EditorOptions {
  /**
   * Container element.
   */
  container: HTMLElement

  /**
   * Initial value.
   */
  value?: RichTextValue

  /**
   * Placeholder text.
   */
  placeholder?: string

  /**
   * Toolbar configuration key or custom config.
   */
  toolbar?: string | ToolbarConfig

  /**
   * Read-only mode.
   */
  readOnly?: boolean

  /**
   * Custom formats to register.
   */
  formats?: FormatType[]

  /**
   * Theme name.
   */
  theme?: string

  /**
   * Additional modules/plugins configuration.
   */
  modules?: Record<string, unknown>
}

FormatButton

Format button with options.

interface FormatButton {
  /**
   * Format type.
   */
  type: FormatType

  /**
   * Options for the format (e.g., header levels, colors).
   */
  options?: (string | number | boolean)[]
}

RichTextEditor

Rich text editor instance with methods for content manipulation, formatting, and event handling.

interface RichTextEditor {
  /**
   * Gets the current content value.
   */
  getValue(): RichTextValue

  /**
   * Sets the content value.
   */
  setValue(value: RichTextValue): void

  /**
   * Gets the plain text content.
   */
  getText(): string

  /**
   * Gets the HTML content.
   */
  getHTML(): string

  /**
   * Gets the content length.
   */
  getLength(): number

  /**
   * Inserts text at the current cursor position.
   */
  insertText(text: string, index?: number): void

  /**
   * Inserts HTML at the current cursor position.
   */
  insertHTML(html: string, index?: number): void

  /**
   * Inserts an embed (image, video, etc.).
   */
  insertEmbed(type: string, value: unknown, index?: number): void

  /**
   * Deletes content.
   */
  deleteText(index: number, length: number): void

  /**
   * Formats text.
   */
  format(format: FormatType, value?: unknown): void

  /**
   * Formats text at a specific range.
   */
  formatText(index: number, length: number, format: FormatType, value?: unknown): void

  /**
   * Removes formatting.
   */
  removeFormat(index: number, length: number): void

  /**
   * Gets the current selection.
   */
  getSelection(): SelectionRange | null

  /**
   * Sets the selection.
   */
  setSelection(index: number, length?: number): void

  /**
   * Focuses the editor.
   */
  focus(): void

  /**
   * Blurs the editor.
   */
  blur(): void

  /**
   * Checks if the editor has focus.
   */
  hasFocus(): boolean

  /**
   * Enables the editor.
   */
  enable(): void

  /**
   * Disables the editor.
   */
  disable(): void

  /**
   * Checks if the editor is enabled.
   */
  isEnabled(): boolean

  /**
   * Subscribes to editor events.
   */
  on<T>(event: EditorEvent, handler: EditorEventHandler<T>): () => void

  /**
   * Removes event handler.
   */
  off<T>(event: EditorEvent, handler: EditorEventHandler<T>): void

  /**
   * Gets the underlying editor instance (for advanced usage).
   */
  getEditorInstance(): unknown

  /**
   * Destroys the editor.
   */
  destroy(): void
}

RichTextProvider

Rich text editor provider interface for creating editors and converting content formats.

interface RichTextProvider {
  /**
   * Create a new rich text editor instance attached to a container element.
   * @returns A RichTextEditor instance for controlling the editor.
   */
  createEditor(options: EditorOptions): RichTextEditor

  /**
   * Get the name of this rich text provider (e.g., 'quill', 'tiptap', 'slate').
   * @returns The provider name string.
   */
  getName(): string

  /**
   * Get the available toolbar configuration presets (e.g., 'minimal', 'standard', 'full').
   * @returns A map of preset names to their ToolbarConfig definitions.
   */
  getToolbarPresets(): Record<string, ToolbarConfig>

  /**
   * Convert an HTML string to the editor's internal rich text format.
   * @returns A RichTextValue in the provider's internal format.
   */
  htmlToValue(html: string): RichTextValue

  /**
   * Convert a plain text string to the editor's internal rich text format.
   * @returns A RichTextValue in the provider's internal format.
   */
  textToValue(text: string): RichTextValue

  /**
   * Create an empty rich text value suitable for initializing an editor.
   * @returns An empty RichTextValue.
   */
  createEmptyValue(): RichTextValue
}

RichTextValue

Rich text content value.

interface RichTextValue {
  /**
   * Plain text content.
   */
  text: string

  /**
   * HTML content.
   */
  html: string

  /**
   * Delta/JSON representation (if supported by the editor).
   */
  delta?: unknown
}

SelectionChangeData

Data emitted when the editor selection changes.

interface SelectionChangeData {
  /**
   * New selection range.
   */
  range: SelectionRange | null

  /**
   * Previous selection range.
   */
  previousRange: SelectionRange | null

  /**
   * Source of the change.
   */
  source: 'user' | 'api' | 'silent'
}

SelectionRange

Selection range in the editor.

interface SelectionRange {
  /**
   * Start index.
   */
  index: number

  /**
   * Length of selection.
   */
  length: number
}

TextChangeData

Data emitted when the editor content changes.

interface TextChangeData {
  /**
   * New value.
   */
  value: RichTextValue

  /**
   * Previous value.
   */
  previousValue: RichTextValue

  /**
   * Source of the change.
   */
  source: 'user' | 'api' | 'silent'
}

ToolbarConfig

Rich text editor toolbar layout (named preset with grouped format buttons).

interface ToolbarConfig {
  /**
   * Toolbar name/key.
   */
  name: string

  /**
   * Toolbar groups - each group is an array of format buttons.
   */
  groups: ToolbarGroup[]
}

Types

EditorEvent

Editor event types.

type EditorEvent = 'text-change' | 'selection-change' | 'focus' | 'blur'

EditorEventHandler

Event handler for editor events.

type EditorEventHandler<T = unknown> = (data: T) => void

FormatType

Editor format types.

type FormatType =
  | 'bold'
  | 'italic'
  | 'underline'
  | 'strike'
  | 'link'
  | 'image'
  | 'video'
  | 'blockquote'
  | 'code-block'
  | 'header'
  | 'list'
  | 'indent'
  | 'align'
  | 'color'
  | 'background'
  | 'font'
  | 'size'
  | 'script'
  | 'direction'
  | 'clean'

ToolbarGroup

A group of format buttons displayed together in the toolbar (e.g. [bold, italic, underline]).

type ToolbarGroup = (FormatType | FormatButton)[]

Functions

createEditor(options)

Create a new rich text editor instance using the current provider.

function createEditor(options: EditorOptions): RichTextEditor
  • options — Editor configuration (container, toolbar, initial value, etc.).

Returns: A RichTextEditor instance for controlling the editor.

createEmptyValue()

Create an empty rich text value suitable for initializing an editor.

function createEmptyValue(): RichTextValue

Returns: An empty RichTextValue in the provider's internal format.

createSimpleRichTextProvider()

Create a simple contentEditable-based rich text provider. This is a basic fallback — for production use, prefer a dedicated provider like @molecule/app-rich-text-quill.

function createSimpleRichTextProvider(): RichTextProvider

Returns: A RichTextProvider using the browser's contentEditable API.

getProvider()

Get the current rich text provider. Falls back to a simple contentEditable-based provider if none has been explicitly set.

function getProvider(): RichTextProvider

Returns: The active RichTextProvider instance.

hasProvider()

Check if a rich text provider has been registered.

function hasProvider(): boolean

Returns: Whether a RichTextProvider has been bonded.

htmlToValue(html)

Convert an HTML string to the provider's internal rich text format.

function htmlToValue(html: string): RichTextValue
  • html — The HTML string to convert.

Returns: A RichTextValue representing the HTML content.

setProvider(provider)

Set the rich text provider.

function setProvider(provider: RichTextProvider): void
  • provider — RichTextProvider implementation to register.

textToValue(text)

Convert a plain text string to the provider's internal rich text format.

function textToValue(text: string): RichTextValue
  • text — The plain text string to convert.

Returns: A RichTextValue representing the text content.

Constants

defaultToolbars

Default toolbar presets.

const defaultToolbars: Record<string, ToolbarConfig>

Injection Notes

Requirements

Peer dependencies:

  • @molecule/app-bond ^1.0.1

Runtime Dependencies

  • @molecule/app-bond

  • dompurify

  • Toolbar presets are 'minimal' | 'standard' | 'full' (see defaultToolbars). There is no 'basic' preset — the quill bond silently substitutes standard for unknown names.

  • If you never call setProvider(), the first editor call silently self-bonds a minimal contentEditable fallback: NO toolbar UI, no delta support, basic formatting only. Fine for plain notes; wire the quill bond for real editing. hasProvider() reports whether a provider was explicitly bonded before this fallback kicks in.

  • The fallback sanitizes all HTML through DOMPurify (bundled). Other providers own their own sanitization — always treat stored HTML as untrusted when rendering outside the editor.

  • Browser-only: createEditor touches document/window — do not call during SSR.