Documentation · itzsa

TipTap Rich Text Editor — @itzsa/editor

TipTap rich text editor with toolbar, HTML mode, tables and media, Nepali Unicode/Preeti, language lock, and sanitized HTML/URL ingress.

@itzsa/editorTipTapUnicode / Preeti

Installation#

Peer-friendly TipTap editor. Add nepali-input when using Nepali modes.

pnpm add @itzsa/editor @itzsa/nepali-input
@source "../node_modules/@itzsa/editor";
@import "@itzsa/editor/styles.css";

Live demo#

Loading editor…

Uploads use onUpload → https URL (no base64)

Starter#

Controlled HTML plus a host-owned upload handler.

"use client";

import { useState } from "react";
import {
  RichTextEditor,
  type EditorUploadHandler,
} from "@itzsa/editor";
import "@itzsa/editor/styles.css";

const onUpload: EditorUploadHandler = async (file, { signal, onProgress }) => {
  const body = new FormData();
  body.append("file", file);
  const res = await fetch("/api/upload", { method: "POST", body, signal });
  if (!res.ok) throw new Error("Upload failed");
  onProgress({ ratio: 1 });
  const { url } = await res.json();
  return url; // https://cdn.example.com/...
};

export function Example() {
  const [html, setHtml] = useState("<p>Hello</p>");

  return (
    <RichTextEditor
      value={html}
      onChange={setHtml}
      onUpload={onUpload}
      settings={{
        nepali: "unicode",
        maxLength: 5000,
        media: { maxImageBytes: 5_000_000 },
      }}
    />
  );
}

Uploads#

Files are never inlined as base64.

Pass onUpload or settings.media.onUpload that returns a durable https:// CDN URL. URL paste still works without an uploader when allowUrlInsert is true.

settings.media

PropTypeDefaultDescription
onUploadEditorUploadHandler-(file, { kind, signal, onProgress }) => Promise<httpsUrl>. Required for file pick / drag-drop.
maxImageBytesnumber5MBMax image upload size in bytes.
maxVideoBytesnumber50MBMax video upload size in bytes.
acceptImagereadonly string[]png/jpeg/gif/webpAllowed image MIME types.
acceptVideoreadonly string[]mp4/webm/oggAllowed video MIME types.
allowUrlInsertbooleantrueAllow pasting an https media URL without uploading a file.

Settings#

Prefer the settings bag for production wiring; flat props still merge.

settings={{
  nepali: "unicode",
  maxLength: 5000,
  compact: true,
  showStatusBar: true,
  allowHtmlMode: true,
  sanitize: true,
  toolbar: { video: false, html: false },
  media: {
    onUpload,
    maxImageBytes: 5_000_000,
    maxVideoBytes: 50_000_000,
    allowUrlInsert: true,
  },
  locale: { placeholder: "लेख्नुहोस्…" },
  classNames: { root: "my-editor" },
}}

EditorSettings

PropTypeDefaultDescription
placeholderstring-Empty state placeholder text.
nepali"unicode" | "preeti" | falsefalseNepali input mode for the document.
maxLengthnumber-Character limit shown in the status bar.
minHeight / compactstring / boolean-Layout density and content min-height.
showStatusBarbooleantrueShow or hide the bottom status bar.
allowHtmlModebooleantrueEnable HTML source mode in the toolbar.
sanitizebooleantrueRun HTML / URL sanitizers on ingress.
immediatelyRenderbooleanfalseTipTap SSR-related render flag.
toolbarEditorToolbarFeatures-Per-feature toolbar flags (see toolbar table).
classNamesEditorClassNames-Class name slots for chrome regions.
localePartial<EditorLocaleText>-Partial locale string overrides.
extensionsExtensions-Additional TipTap extensions.
mediaEditorMediaSettings-Upload handler, size limits, MIME accept lists, URL insert.

Security#

Sanitization on ingress — still sanitize again when rendering stored HTML.

  • HTML sanitizer on value, paste, and HTML mode
  • URL allowlist — blocks javascript:, data: (unless explicitly allowed), and protocol-relative phishing URLs
  • Safe CSS lengths only for width / font-size
  • Video via schema node — no HTML string injection
  • Prefer onUpload for production media

Rendering

Sanitize again before dangerouslySetInnerHTML. See the package README.

Security helpers

PropTypeDefaultDescription
sanitizeHtml(html: string) => string-Sanitize HTML before storage or display.
sanitizeUrl / validateLinkHrefURL helpers-Allowlist http(s) and relative URLs; block javascript: / data:.
sanitizeCssLength(value: string) => string | null-Safe CSS length for width / font-size attributes.
validateMediaInsertmedia guard-Validate media URLs before insert.

Props API#

Full prop tables for RichTextEditor, toolbar, classNames, and the ref handle.

RichTextEditor#

Top-level component props. Flat props merge with settings.

RichTextEditorProps

PropTypeDefaultDescription
valuestring""Controlled HTML content.
onChange(html: string) => void-Fires when the document HTML changes.
onBlur / onFocus() => void-Focus lifecycle callbacks.
refRef<RichTextEditorHandle>-Imperative API: getHTML, getJSON, getText, setContent, clear, focus, blur, isEmpty, getEditor.
labelstring-Optional visible label above the editor.
placeholderstring-Empty-document placeholder (also via settings / locale).
disabledbooleanfalseDisables editing and toolbar actions.
readOnlybooleanfalseView-only content; toolbar stays mostly inactive.
invalidbooleanfalseShows invalid / error border styling.
nepali"unicode" | "preeti" | falsefalseEnable Nepali transliteration input (requires @itzsa/nepali-input).
maxLengthnumber-Soft character limit; status bar warns when reached.
minHeightstring-Editor surface min-height CSS value (e.g. "220px").
compactbooleanfalseTighter toolbar and content padding.
showStatusBarbooleantrueWord / character counts and limit messaging.
allowHtmlModebooleantrueAllow switching to raw HTML editing panel.
sanitizebooleantrueSanitize HTML on value, paste, setContent, and HTML mode apply.
immediatelyRenderbooleanfalseTipTap immediatelyRender (prefer false under SSR / Next.js).
onUploadEditorUploadHandler-Host uploader for device files. Prefer settings.media.onUpload in production.
maxUploadBytesnumber-Deprecated — use settings.media.maxImageBytes / maxVideoBytes.
toolbarEditorToolbarFeatures-Toggle toolbar groups (history, headings, table, image, …).
classNamestring-Root class name.
classNamesEditorClassNames-Slots: root, toolbar, content, statusBar, htmlPanel.
localePartial<EditorLocaleText>-Override toolbar / modal / status strings.
extensionsExtensions-Extra TipTap extensions merged into the editor schema.
settingsEditorSettings-Scalable config bag. Flat props merge with / override matching settings keys.

Toolbar features#

Pass via toolbar or settings.toolbar.

EditorToolbarFeatures

PropTypeDefaultDescription
historybooleantrueUndo / redo.
headingsbooleantrueHeading level controls.
fontsbooleantrueFont family / size controls.
marksbooleantrueBold, italic, underline, strike, highlight.
colorbooleantrueText color picker.
transform / scriptbooleantrueCase transform and sub/superscript.
link / code / htmlbooleantrueLink popup, inline/block code, HTML mode toggle.
align / lists / quotebooleantrueAlignment, lists, and blockquote.
table / image / video / rulebooleantrueInsert table, image, video, horizontal rule.

Class names#

Slot class names for chrome regions.

EditorClassNames

PropTypeDefaultDescription
rootstring-Outer editor chrome.
toolbarstring-Toolbar row.
contentstring-ProseMirror / EditorContent surface.
statusBarstring-Bottom status bar.
htmlPanelstring-Raw HTML mode panel.

Ref handle#

Imperative API via ref.

RichTextEditorHandle

PropTypeDefaultDescription
getHTML()() => string-Current document as HTML.
getJSON()() => Record<string, unknown>-TipTap JSON document.
getText()() => string-Plain text content.
setContent(html, options?)(html, { emitUpdate? }) => void-Replace content; optionally emit onChange.
clear()() => void-Clear the document.
focus() / blur()() => void-Focus or blur the editor surface.
isEmpty()() => boolean-Whether the document is empty.
getEditor()() => Editor | null-Underlying TipTap instance (advanced).