SVeditor Docs
Integrations

ESM package integration

Install and use @wztlink1013/sveditor as the default ESM package in React, Next.js, and Vite apps.

ESM package integration

ESM via npm is the default integration path. Install @wztlink1013/sveditor, import it in your bundler, and mount with SVeditor.create(). Use the UMD CDN only when you cannot add a bundler.

Packages

PackageWhen to install
@wztlink1013/sveditorAlways — editor runtime, UI, types, and styles
@wztlink1013/sveditor-collab-schemaOnly when your server implements collaboration APIs

When you use the collab schema, keep both packages on the same version.

1. Install

If your license includes private registry access, add .npmrc in the project root:

@wztlink1013:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${NPM_TOKEN}

Install a pinned version:

pnpm add @wztlink1013/sveditor@0.2.16

Use the token provided with your license for CI and fresh machines.

2. Imports

ImportPurpose
@wztlink1013/sveditorSVeditor.create(), types, theme helpers
@wztlink1013/sveditor/style.cssToolbar, editor chrome, toast styles
@wztlink1013/sveditor/globalOptional window.SVeditor typings for CDN pages

Bundlers resolve the ESM entry automatically. Prefer import over require() in application code.

3. Minimal usage

"use client";

import { SVeditor } from "@wztlink1013/sveditor";
import type { EditorOptions } from "@wztlink1013/sveditor";
import "@wztlink1013/sveditor/style.css";

const editor = SVeditor.create({
  el: "#editor",
  content: "<p>Hello</p>",
  editable: true,
} satisfies Omit<EditorOptions, "el">);
  • Always import style.css — missing CSS breaks toolbar and layout.
  • Call destroy() before unmount or navigation.

4. Next.js App Router (SSR-safe)

The ESM bundle may access document during module load. Do not statically import @wztlink1013/sveditor from Server Components.

Option A — next/dynamic with ssr: false

Split the editor into a client-only module, then load it dynamically:

"use client";

import dynamic from "next/dynamic";

export const DocEditor = dynamic(
  () => import("./doc-editor.client").then((m) => m.DocEditor),
  { ssr: false },
);

Inside doc-editor.client.tsx:

"use client";

import { useEffect, useMemo, useRef } from "react";
import { SVeditor } from "@wztlink1013/sveditor";
import type { EditorOptions } from "@wztlink1013/sveditor";
import "@wztlink1013/sveditor/style.css";

type EditorInitOptions = Omit<EditorOptions, "el">;

export function DocEditor({ options }: { options: EditorInitOptions }) {
  const containerRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const el = containerRef.current;
    if (!el) return;
    const editor = SVeditor.create({ el, ...options });
    return () => editor.destroy();
  }, [options]);

  return <div ref={containerRef} className="min-h-[640px]" />;
}

Option B — dynamic import() in useEffect

"use client";

import { useEffect, useRef } from "react";
import type { EditorInstance } from "@wztlink1013/sveditor";
import "@wztlink1013/sveditor/style.css";

export function LazyEditor() {
  const containerRef = useRef<HTMLDivElement>(null);
  const instanceRef = useRef<EditorInstance | null>(null);

  useEffect(() => {
    const el = containerRef.current;
    if (!el) return;

    let cancelled = false;

    void import("@wztlink1013/sveditor").then(({ SVeditor }) => {
      if (cancelled) return;
      instanceRef.current = SVeditor.create({ el, content: "<p>Hello</p>" });
    });

    return () => {
      cancelled = true;
      instanceRef.current?.destroy();
      instanceRef.current = null;
    };
  }, []);

  return <div ref={containerRef} className="min-h-[640px]" />;
}

5. Vite / React SPA

When mount code runs only in the browser, use useEffect and stable options:

"use client";

import { useEffect, useMemo, useRef } from "react";
import { SVeditor } from "@wztlink1013/sveditor";
import type { EditorOptions } from "@wztlink1013/sveditor";
import "@wztlink1013/sveditor/style.css";

type EditorInitOptions = Omit<EditorOptions, "el">;

export function EditorPage() {
  const containerRef = useRef<HTMLDivElement>(null);
  const options = useMemo<EditorInitOptions>(
    () => ({ content: "<p>Hello</p>", editable: true }),
    [],
  );

  useEffect(() => {
    const el = containerRef.current;
    if (!el) return;
    const editor = SVeditor.create({ el, ...options });
    return () => editor.destroy();
  }, [options]);

  return <div ref={containerRef} className="min-h-[640px]" />;
}

See Quick start for the full lifecycle.

6. Styles and PostCSS

Import SDK styles directly:

import "@wztlink1013/sveditor/style.css";

If PostCSS re-processes node_modules CSS and fails on the pre-built stylesheet, exclude @wztlink1013/sveditor in your PostCSS config.

7. TypeScript

import { SVeditor } from "@wztlink1013/sveditor";
import type {
  EditorOptions,
  EditorInstance,
  ExtensionOptions,
  AutoSaveOptions,
} from "@wztlink1013/sveditor";

8. Upgrade

  1. Bump the version in package.json.
  2. Reinstall dependencies.
  3. Re-test extensionsOptions and collab schema if applicable.

Troubleshooting

SymptomFix
document is not definedUse next/dynamic + ssr: false or dynamic import() in useEffect
Broken toolbarAdd import "@wztlink1013/sveditor/style.css"
Focus lost on keystrokeStabilize options with useMemo
Install auth errorsCheck .npmrc and your license token
PostCSS parse errorExclude SDK CSS from PostCSS

Next steps