@xinosolutions/editor
v1.1.7
Published
Professional rich text editor component for React with customizable toolbar, theming, and access validation.
Readme
@xinosolutions/editor
Production-capable rich text editor component for React applications.
About XinoSolutions
XinoSolutions is a software development company dedicated to creating high-quality, developer-friendly solutions. We specialize in building modern React components and tools that help developers build better applications faster. Our commitment to excellence, clean code, and user experience drives everything we create.
This package is part of our open-source initiative to contribute valuable tools to the React ecosystem.
@xinosolutions/editor provides a WYSIWYG editing experience with customizable toolbar/navbar layouts, theme configuration, image upload hooks, and optional access validation through Xino API keys.
Why use this package
- Fast integration into existing React apps
- Rich formatting controls out of the box
- Extensible toolbar and navbar configuration
- Browser-safe access validation using
apiKey - Suitable for product forms, CMS flows, support tools, and admin panels
Installation
npm install @xinosolutions/editoryarn add @xinosolutions/editorPeer Dependencies
react^18.2.0react-dom^18.2.0
Quick Start
import { useState } from "react";
import ReactEditor from "@xinosolutions/editor";
export default function App() {
const [value, setValue] = useState("");
return (
<ReactEditor
value={value}
onChange={setValue}
placeholder="Write your content..."
height="420px"
/>
);
}Access Validation
For client-side applications, pass your API key as apiKey (xs_editor_...).
Get your API key here: https://editor.xinosolutions.com/
- Create an editor site and domain allow-list in SX Editor
- No customer backend is required — the API key is safe in browser env vars
- Validation defaults to
https://api.editor.xinosolutions.com/api/text_editor/validate - Host apps can override with
window.__TEXT_EDITOR_VALIDATE_URLorNEXT_PUBLIC_TEXT_EDITOR_VALIDATE_URL/VITE_TEXT_EDITOR_VALIDATE_URL(e.g. same-origin/api/text_editor/validate) - If the host app uses CSP, allow
https://api.editor.xinosolutions.cominconnect-src(andimg-srcif you use image upload) - Optional: same-origin proxy via
@xinosolutions/editor/proxy/nextwhen you prefer not to openconnect-src - Validation help links/messages are handled internally by the package
Environment Variables
Vite:
VITE_TEXT_EDITOR_API_KEY=xs_editor_your_id_here
# Optional — local/dev validate & upload endpoints
# VITE_TEXT_EDITOR_VALIDATE_URL=/api/text_editor/validate
# VITE_TEXT_EDITOR_UPLOAD_URL=/api/text_editor/upload_imageNext.js:
NEXT_PUBLIC_TEXT_EDITOR_API_KEY=xs_editor_your_id_here
# Optional — local/dev validate & upload endpoints
# NEXT_PUBLIC_TEXT_EDITOR_VALIDATE_URL=/api/text_editor/validate
# NEXT_PUBLIC_TEXT_EDITOR_UPLOAD_URL=/api/text_editor/upload_imageUsage:
const apiKey =
import.meta?.env?.VITE_TEXT_EDITOR_API_KEY ??
process.env.NEXT_PUBLIC_TEXT_EDITOR_API_KEY ??
"";
<ReactEditor value={value} onChange={setValue} apiKey={apiKey} />;API Reference (Props)
| Prop | Type | Default | Description |
|---|---|---|---|
| value | string | "" | Current editor HTML/text content. |
| onChange | (nextValue: string) => void | undefined | Change callback for editor content. |
| placeholder | string | internal | Placeholder text when editor is empty. |
| height | string \| number | internal | Editor height (for example "400px" or 500). |
| mainProps | object | {} | Props passed to the editor root wrapper. |
| apiKey | string | "" | API key for access validation (xs_editor_...). |
| onAccessChange | ({ status, access, message? }) => void | undefined | Access-state callback (checking, allowed, denied, error). |
| toolbarDensity | "comfortable" \| "compact" | "comfortable" | Toolbar spacing density. |
| navbar | Array | internal | Override navbar groups/options. |
| toolbar | Array | internal | Override toolbar controls. |
| remove_from_navbar | Array | [] | Remove selected navbar items. |
| remove_from_toolbar | Array | [] | Remove selected toolbar items. |
| theme_config | object | {} | CSS variable-based editor theme overrides. |
| image_handler | (payload) => Promise<string> | undefined | Async image uploader returning a final URL string. |
| handleFullScreen | (isFullScreen: boolean) => void | undefined | Called when fullscreen mode toggles. |
| getEditorRef | (ref) => void | undefined | Access editor ref for advanced integrations. |
Access-State Example
<ReactEditor
value={value}
onChange={setValue}
apiKey={apiKey}
onAccessChange={({ status }) => setCanSave(status === "allowed")}
/>Custom Toolbar and Navbar
const navbar = [
{ name: "file", options: ["new_document", "preview", "print"] },
{ name: "view", options: ["source_code", "full_screen"] },
{ name: "insert", options: ["image", "link", "video", "hr_line", "special_char"] },
{ name: "format", options: ["bold", "italic", "underline", "font", "font_size", "alignment"] },
"|",
"select_all",
];
const toolbar = [
"undo", "redo", "|", "bold", "italic", "underline", "|", "alignment", "|", "orderedList", "unorderedList",
];
<ReactEditor value={value} onChange={setValue} navbar={navbar} toolbar={toolbar} />;Remove actions:
<ReactEditor
value={value}
onChange={setValue}
remove_from_toolbar={["bold", { name: "format", options: ["h1"] }]}
remove_from_navbar={["select_all", { name: "view", options: ["source_code"] }]}
/>Theme Customization
const theme_config = {
"background-color": "#ffffff",
"border-color": "#d0d5dd",
"text-color": "#101828",
"toolbar-button-background": "#ffffff",
"toolbar-text-color": "#101828",
"toolbar-button-hover-background": "#f2f4f7",
"toolbar-button-selected-background": "#eaecf0",
"svg-color": "#101828",
};
<ReactEditor value={value} onChange={setValue} theme_config={theme_config} />;Image Upload Integration
The editor package talks to POST /api/text_editor/upload_image on the XS Editor API (same API key + domain allow-list as validate). Use the built-in helper:
import ReactEditor, {
createEditorImageHandler,
} from "@xinosolutions/editor";
const apiKey =
import.meta?.env?.VITE_TEXT_EDITOR_API_KEY ??
process.env.NEXT_PUBLIC_TEXT_EDITOR_API_KEY ??
"";
const image_handler = createEditorImageHandler({ apiKey });
<ReactEditor
value={value}
onChange={setValue}
apiKey={apiKey}
image_handler={image_handler}
/>;Optional local overrides (same pattern as validate):
# Vite
VITE_TEXT_EDITOR_UPLOAD_URL=/api/text_editor/upload_image
# Next.js
NEXT_PUBLIC_TEXT_EDITOR_UPLOAD_URL=/api/text_editor/upload_imageOr set window.__TEXT_EDITOR_UPLOAD_URL at runtime. When unset, the upload URL is derived from the validate URL (…/validate → …/upload_image).
Custom handler (if you proxy through your own backend):
async function image_handler(payload) {
const formData = new FormData();
formData.append("image", payload.image);
formData.append("api_key", apiKey);
const response = await fetch("/api/text_editor/upload_image", {
method: "POST",
headers: { "x-editor-api-key": apiKey },
body: formData,
});
const data = await response.json();
return data?.image_url ?? "";
}Upload accepts JPEG, PNG, GIF, and WebP up to 15MB. The response includes image_url (public URL for the editor) and image_path (storage key).
Security Recommendations
- Register every production hostname in your editor site’s allowed domains.
- Use
apiKeyfrom environment variables — do not hard-code in source. - Enforce authorization again on your own save/upload endpoints if you add a backend later.
- The editor sanitizes inbound HTML (paste, source, embeds, controlled
value) with DOMPurify. Host apps should still sanitize when rendering saved HTML outside the editor. - Paste defaults to Word / Google Docs–style cleaning: structure and semantic formatting are kept; source
style/classand similar presentational attributes are stripped. Use Ctrl/Cmd+Shift+V to paste as plain text. - Prefer
http:/https:/mailto:links;javascript:and similar schemes are rejected.
Troubleshooting
- Editor remains locked: verify domain allow-list and key type in the portal.
- Validation endpoint errors: verify your API key and domain allow-list in the portal.
- Visual issues: confirm package styles are loaded and not overridden by aggressive global CSS resets.
- Image upload fails: ensure
image_handlerresolves to a valid absolute URL.
License
MIT
Support
For product or integration support, contact Xino Solutions.
