Package Exports
- @veztraa/editor
Readme
@veztraa/editor
A full-featured, zero-config WYSIWYG rich-text editor as a single React component. Drop <Editor /> into any React app and your users get a modern editing experience in seconds — a Notion-style slash menu, a floating selection toolbar, Markdown shortcuts, a full emoji picker, live code-block syntax highlighting, image uploads, and clean semantic HTML out.
TypeScript-first, framework-agnostic (React 18 & 19, Next.js App Router, Vite), dark mode built in. Styles auto-inject on mount — no CSS import required.
Installation
npm install @veztraa/editorQuick start
import { useState } from "react";
import { Editor } from "@veztraa/editor"; // styles auto-inject — no CSS import
export default function App() {
const [html, setHtml] = useState("<p>Hello world</p>");
return <Editor value={html} onChange={setHtml} height={400} />;
}Modal mode
<EditorModal /> renders in a fullscreen portal and commits changes only when the user clicks Done.
import { EditorModal } from "@veztraa/editor";
{open && (
<EditorModal
value={content}
onChange={(html) => { save(html); setOpen(false); }}
onClose={() => setOpen(false)}
title="Edit content"
/>
)}Features
- Slash menu — type
/for headings, lists, tables, images, code blocks, and more - Bubble toolbar — a formatting bar that appears over selected text
- Markdown shortcuts —
#,-,1.,>,```,**bold**,*italic*,`code`,~~strike~~format as you type - Emoji picker — the full 1,900+ Unicode set in a categorized grid, plus
:shortcode:autocomplete - Code blocks — live syntax highlighting
- Autolink — URLs become links as you type
- URL auto-embed — paste a YouTube/Vimeo link → a responsive, sandboxed embed
- Images — drag-drop, paste (incl. screenshots), or the toolbar button; inline base64 by default or upload to your server via
onImageUpload - Tables, text/background color, alignment, indent, sub/superscript, find & replace, print
- Character limit with a live counter (
maxLength) - Extensible — add your own slash commands and toolbar buttons
- Clean output — semantic HTML via
onChange, plus asanitizeHtml()helper - Dark & light themes, one-hex
accentColor, controlled or uncontrolled
Framework notes
- Vite / CRA — import and use, nothing extra.
- Next.js (App Router) — the editor renders on the client. Mark the file
"use client", or import it withnext/dynamicand{ ssr: false }. Importing the package in a server file is safe (it touches no DOM at import time). No CSS import is needed — styles inject on first render. sanitizeHtml()runs in the browser — your editor value already lives client-side, so sanitize there before submitting.
Key props
| Prop | Type | Description |
|---|---|---|
value |
string |
HTML content (controlled). |
onChange |
(html: string) => void |
Fires on every change with the current HTML. |
placeholder |
string |
Placeholder shown when empty. |
height |
number | string |
Editor height (px number or any CSS value). |
theme |
"light" | "dark" |
Controlled color theme. |
readOnly |
boolean |
Display content without editing. |
accentColor |
string |
6-digit hex driving buttons, focus rings, active states. |
maxLength |
number |
Hard character cap; the counter turns red at the limit. |
onImageUpload |
(file: File) => Promise<string> | string |
Upload handler for dropped/pasted/picked images; return the hosted URL. Omit to inline as base64. |
slashCommands |
SlashCommand[] |
Extra entries for the / menu. |
toolbarButtons |
ToolbarButton[] |
Extra toolbar buttons (icon + action). |
onFocus / onBlur |
() => void |
Focus / blur of the editing area. |
onLinkClick |
(href, event) => void |
Link clicks; call event.preventDefault() to handle navigation yourself. |
slashMenu / bubbleToolbar / statusBar |
boolean |
Toggle the premium UI layers (all default true). |
config |
object |
Passthrough to the underlying engine options. |
EditorProps, EditorModalProps, SlashCommand, and ToolbarButton are all exported.
Recipes
Upload images to your server
<Editor
value={html}
onChange={setHtml}
onImageUpload={async (file) => {
const body = new FormData();
body.append("file", file);
const res = await fetch("/api/upload", { method: "POST", body });
const { url } = await res.json();
return url; // inserted as <img src={url}>
}}
/>Custom slash commands
<Editor
value={html}
onChange={setHtml}
slashCommands={[
{
title: "Callout",
description: "Highlighted note box",
action: ({ insertHTML }) =>
insertHTML("<blockquote>💡 <strong>Note:</strong> …</blockquote>"),
},
]}
/>Custom toolbar buttons
<Editor
value={html}
onChange={setHtml}
toolbarButtons={[
{
name: "insertDate",
tooltip: "Insert today's date",
iconSvg: '<svg class="rte-mico" viewBox="0 0 24 24"><rect x="3" y="4" width="18" height="18" rx="2"/><path d="M3 10h18"/></svg>',
exec: ({ insertText }) => insertText(new Date().toLocaleDateString()),
},
]}
/>Sanitize before you store
import { sanitizeHtml } from "@veztraa/editor";
const clean = sanitizeHtml(dirtyHtml); // allowlist: safe tags, attrs & styles onlyLicense
MIT © Veztraa Solutions. This package bundles a modified third-party editor engine under its own MIT license; see THIRD-PARTY-NOTICES.txt.