npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@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/editor
yarn add @xinosolutions/editor

Peer Dependencies

  • react ^18.2.0
  • react-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_URL or NEXT_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.com in connect-src (and img-src if you use image upload)
  • Optional: same-origin proxy via @xinosolutions/editor/proxy/next when you prefer not to open connect-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_image

Next.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_image

Usage:

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_image

Or 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 apiKey from 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 / class and 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_handler resolves to a valid absolute URL.

License

MIT

Support

For product or integration support, contact Xino Solutions.