Tiptap image upload: give one handler ownership of a pasted image

Tiptap's Image extension displays image nodes; it does not upload files. FileHandler exposes pasted and dropped files for your application to process. When a paste contains both a file and HTML, configure paste ownership deliberately or separate handlers can insert the same image twice. Image extension, FileHandler extension

In an original field notebook, a researcher copies one camera-trap image from another application. The clipboard may contain an image file and an HTML fragment. The desired result is one stored photograph beside the observation, not one uploaded image plus a second image created from the clipboard HTML.

Separate the node from the file callback

Enable Image in the existing editor to represent stored image references. FileHandler supplies onPaste(editor, files, htmlContent) and onDrop(editor, files, pos) callbacks. The paste callback receives any accompanying HTML; the drop callback receives the document drop position.

The callbacks are integration points. Your application still needs to validate and upload the file, obtain a durable image address, insert an image node, report failures, and save the document. There is no universal upload-response property imposed by the Image extension.

The Quill image upload guide explains the broader distinction between uploading media and saving its reference. In Tiptap, the extra problem here is deciding which clipboard representation owns insertion.

Consume the paste only when your handler owns its content

The current FileHandler documentation describes consumePasteEvent, with a default of false. Setting it to true fully consumes file-bearing paste events even when HTML accompanies the files. This prevents other extensions' paste handling from creating duplicate content.

For a notebook that deliberately handles only pasted still-image files, the relevant configuration shape is:

FileHandler.configure({
  allowedMimeTypes: ['image/jpeg', 'image/png'],
  consumePasteEvent: true,
  onPaste: (editor, files, htmlContent) => {
    // Application owns this file-bearing paste.
    // Pass accepted files to the existing upload workflow.
    // Insert one image per successful upload; show failures.
  }
});

FileHandler comes from @tiptap/extension-file-handler. Add it to the initialized application's extension configuration alongside Image and its document support. This is a callback wiring fragment, not a working uploader. Replace the comments with the existing workflow before enabling it for authors.

Consuming the paste can also suppress accompanying text or formatting that another handler would have inserted. Define whether the notebook accepts image-only paste or mixed content, then test that exact policy. Do not enable the option merely to hide duplicates while silently losing text the researcher expects to retain.

Inspect files and HTML before choosing a representation

The official documentation warns that copying a GIF from another application can expose a single-frame file alongside an HTML image address. If preserving animation matters, blindly uploading the file may lose it. Inspect the actual clipboard representations and define an allowed, durable source route; do not insert arbitrary clipboard HTML as trusted content.

For this notebook, the documented example accepts JPEG and PNG still images. Client MIME filtering is a convenience; the upload service must enforce actual permitted content and access rules. Image's allowBase64 option controls parsing data-URL images and defaults to false; enabling it does not upload a file or establish durable storage.

For asynchronous drop handling, the supplied numeric position describes the document at the drop event. If edits can occur before upload finishes, preserve placement through document changes or deliberately hold editing. An old position is not automatically a durable location.

Check one paste all the way to the saved notebook

In the real application, paste one still photograph whose clipboard includes HTML. Inspect the upload request and count the resulting image nodes: one accepted file should produce one intended node. Also paste ordinary text, try a rejected file, and test mixed text with an image according to the chosen policy.

Reopen the notebook and load the photograph as its intended reader. The final record should contain one camera-trap image with its observation intact, and an upload failure should remain a visible failure rather than an apparently successful saved entry.

Keep reading