SVeditor Docs
Editing

Images & attachments

Configure extensionsOptions.image and attachment onUpload, proxyUrl, and failure notifications.

Images & attachments

SVeditor supports resizable images and attachment cards (name, size, download link). Both are wired through extensionsOptions: the SDK handles toolbar actions, paste, drag-and-drop, and node rendering; upload and auth are yours.

Typical steps:

  1. Implement onUpload to send File objects to your storage or API and return node attributes.
  2. Optionally set proxyUrl so documents store relative keys while the UI uses a CDN root.
  3. Optionally tune extensionsOptions.notifications for failure toasts.

Integrate in a Next.js app

1. Image upload

import type { ImageOptions } from "@wztlink1013/sveditor";

const imageOptions: ImageOptions = {
  proxyUrl: "https://cdn.example.com",
  onUpload: async (file, onProgress) => {
    onProgress?.({ progress: 10 });

    const signed = await fetch("/api/upload/image/signed-url", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        filename: file.name,
        contentType: file.type,
      }),
    });

    if (!signed.ok) {
      throw new Error("Failed to get signed URL");
    }

    const { uploadUrl, publicPath } = await signed.json();

    await uploadWithProgress(uploadUrl, file, (p) =>
      onProgress?.({ progress: p }),
    );

    return {
      src: publicPath,
      alt: file.name.replace(/\.[^/.]+$/, ""),
      title: file.name,
      width: 1200,
      height: 800,
      "data-keep-ratio": true,
    };
  },
};

SVeditor.create({
  el: "#editor",
  extensionsOptions: { image: imageOptions },
});

onUpload must resolve with image attributes or throw so the SDK can show failure UI. Do not swallow errors.

2. Attachment upload

import type { AttachmentOptions } from "@wztlink1013/sveditor";

const attachmentOptions: AttachmentOptions = {
  onUpload: async (file, onProgress) => {
    onProgress?.({ progress: 50 });
    const { url } = await uploadFileToStorage(file);
    onProgress?.({ progress: 100 });

    return {
      src: url,
      name: file.name,
      size: file.size,
      type: file.type || "application/octet-stream",
    };
  },
};

SVeditor.create({
  el: "#editor",
  extensionsOptions: { attachment: attachmentOptions },
});

3. 在 React 中组合

const options = useMemo(
  () => ({
    extensionsOptions: {
      image: { onUpload: uploadImage, proxyUrl: CDN_ROOT },
      attachment: { onUpload: uploadAttachment },
      autoSave: { onSaveContent: saveBody },
    },
  }),
  [docId],
);

return <SveditorMount options={options} />;

See Playground for a live upload example.

Options

extensionsOptions.image

interface ImageOptions {
  proxyUrl?: string;
  onUpload?: (
    file: File,
    onProgress?: (progress: { progress: number }) => void,
  ) => Promise<ResizableImageHTMLAttributes>;
}
OptionWhenNotes
onUploadInsert / paste / dropReturn src, width, height; src may be a storage key with proxyUrl
proxyUrlSplit CDN vs stored keyPrepended when rendering

Common return fields:

FieldPurpose
srcRequired URL or key
width / heightInitial size
data-keep-ratioPrefer true
alt / titleAccessibility

extensionsOptions.attachment

interface AttachmentOptions {
  proxyUrl?: string;
  onUpload?: (
    file: File,
    onProgress?: (progress: { progress: number }) => void,
  ) => Promise<AttachmentHTMLAttributes>;
}
FieldPurpose
srcDownload URL or key
nameDisplay name
sizeBytes
typeMIME for icon

How it works

  1. User picks a file via toolbar, paste, or drag-and-drop.
  2. SDK calls your onUpload (wrapped for notifications).
  3. On success, inserts a resizable image or attachment node; JSON stores src and metadata.
  4. With proxyUrl, displayed URL is proxyUrl + src when src is path-like.

Common patterns

Demo without a backend

The sandbox may fall back to placeholders when signing fails; production should throw so authors see errors.

With auto-save

Upload updates the in-memory document; persistence still happens via debounced onSaveContent. Ensure src remains valid long term.

With auto-save

Upload updates the document JSON; autoSave.onSaveContent persists the updated node data after the debounce window. Make sure stored URLs or keys stay readable after the editor reloads.

Notes

  1. Throw on non-2xx responses so failures surface in the UI.
  2. Enforce size/type limits in your API—the SDK is not a server validator.
  3. Private buckets: store keys in JSON, serve via signed URLs or proxyUrl.
  4. Without onUpload, image/attachment entry points may be disabled depending on the build.

Next steps