Documentation · itzsa
Editor
TipTap rich text editor with toolbar, HTML mode, tables and media, Nepali Unicode/Preeti, language lock, and sanitized HTML/URL ingress.
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#
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
| Prop | Type | Default | Description |
|---|---|---|---|
| onUpload | EditorUploadHandler | — | (file, { kind, signal, onProgress }) => Promise<httpsUrl>. Required for file pick / drag-drop. |
| maxImageBytes | number | 5MB | Max image upload size in bytes. |
| maxVideoBytes | number | 50MB | Max video upload size in bytes. |
| acceptImage | readonly string[] | png/jpeg/gif/webp | Allowed image MIME types. |
| acceptVideo | readonly string[] | mp4/webm/ogg | Allowed video MIME types. |
| allowUrlInsert | boolean | true | Allow 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
| Prop | Type | Default | Description |
|---|---|---|---|
| placeholder | string | — | Empty state placeholder text. |
| nepali | "unicode" | "preeti" | false | false | Nepali input mode for the document. |
| maxLength | number | — | Character limit shown in the status bar. |
| minHeight / compact | string / boolean | — | Layout density and content min-height. |
| showStatusBar | boolean | true | Show or hide the bottom status bar. |
| allowHtmlMode | boolean | true | Enable HTML source mode in the toolbar. |
| sanitize | boolean | true | Run HTML / URL sanitizers on ingress. |
| immediatelyRender | boolean | false | TipTap SSR-related render flag. |
| toolbar | EditorToolbarFeatures | — | Per-feature toolbar flags (see toolbar table). |
| classNames | EditorClassNames | — | Class name slots for chrome regions. |
| locale | Partial<EditorLocaleText> | — | Partial locale string overrides. |
| extensions | Extensions | — | Additional TipTap extensions. |
| media | EditorMediaSettings | — | 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
onUploadfor production media
Security helpers
| Prop | Type | Default | Description |
|---|---|---|---|
| sanitizeHtml | (html: string) => string | — | Sanitize HTML before storage or display. |
| sanitizeUrl / validateLinkHref | URL helpers | — | Allowlist http(s) and relative URLs; block javascript: / data:. |
| sanitizeCssLength | (value: string) => string | null | — | Safe CSS length for width / font-size attributes. |
| validateMediaInsert | media 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
| Prop | Type | Default | Description |
|---|---|---|---|
| value | string | "" | Controlled HTML content. |
| onChange | (html: string) => void | — | Fires when the document HTML changes. |
| onBlur / onFocus | () => void | — | Focus lifecycle callbacks. |
| ref | Ref<RichTextEditorHandle> | — | Imperative API: getHTML, getJSON, getText, setContent, clear, focus, blur, isEmpty, getEditor. |
| label | string | — | Optional visible label above the editor. |
| placeholder | string | — | Empty-document placeholder (also via settings / locale). |
| disabled | boolean | false | Disables editing and toolbar actions. |
| readOnly | boolean | false | View-only content; toolbar stays mostly inactive. |
| invalid | boolean | false | Shows invalid / error border styling. |
| nepali | "unicode" | "preeti" | false | false | Enable Nepali transliteration input (requires @itzsa/nepali-input). |
| maxLength | number | — | Soft character limit; status bar warns when reached. |
| minHeight | string | — | Editor surface min-height CSS value (e.g. "220px"). |
| compact | boolean | false | Tighter toolbar and content padding. |
| showStatusBar | boolean | true | Word / character counts and limit messaging. |
| allowHtmlMode | boolean | true | Allow switching to raw HTML editing panel. |
| sanitize | boolean | true | Sanitize HTML on value, paste, setContent, and HTML mode apply. |
| immediatelyRender | boolean | false | TipTap immediatelyRender (prefer false under SSR / Next.js). |
| onUpload | EditorUploadHandler | — | Host uploader for device files. Prefer settings.media.onUpload in production. |
| maxUploadBytes | number | — | Deprecated — use settings.media.maxImageBytes / maxVideoBytes. |
| toolbar | EditorToolbarFeatures | — | Toggle toolbar groups (history, headings, table, image, …). |
| className | string | — | Root class name. |
| classNames | EditorClassNames | — | Slots: root, toolbar, content, statusBar, htmlPanel. |
| locale | Partial<EditorLocaleText> | — | Override toolbar / modal / status strings. |
| extensions | Extensions | — | Extra TipTap extensions merged into the editor schema. |
| settings | EditorSettings | — | Scalable config bag. Flat props merge with / override matching settings keys. |
Toolbar features#
Pass via toolbar or settings.toolbar.
EditorToolbarFeatures
| Prop | Type | Default | Description |
|---|---|---|---|
| history | boolean | true | Undo / redo. |
| headings | boolean | true | Heading level controls. |
| fonts | boolean | true | Font family / size controls. |
| marks | boolean | true | Bold, italic, underline, strike, highlight. |
| color | boolean | true | Text color picker. |
| transform / script | boolean | true | Case transform and sub/superscript. |
| link / code / html | boolean | true | Link popup, inline/block code, HTML mode toggle. |
| align / lists / quote | boolean | true | Alignment, lists, and blockquote. |
| table / image / video / rule | boolean | true | Insert table, image, video, horizontal rule. |
Class names#
Slot class names for chrome regions.
EditorClassNames
| Prop | Type | Default | Description |
|---|---|---|---|
| root | string | — | Outer editor chrome. |
| toolbar | string | — | Toolbar row. |
| content | string | — | ProseMirror / EditorContent surface. |
| statusBar | string | — | Bottom status bar. |
| htmlPanel | string | — | Raw HTML mode panel. |
Ref handle#
Imperative API via ref.
RichTextEditorHandle
| Prop | Type | Default | Description |
|---|---|---|---|
| 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). |