Skip to content
GitHubDiscord

File

Handle file pasting, dropping, and uploading in the editor.

It's common to upload files to a remote server when pasting or dropping them into the editor. Here are two approaches to implement this functionality:

The simplest method is to update the document after uploading the file and receiving its URL:

import { insertNodefunction insertNode(options: InsertNodeOptions): Command
Returns a command that inserts the given node at the current selection or at the given position.
@public
} from 'prosekit/core'
import { defineFileDropHandlerfunction defineFileDropHandler(handler: FileDropHandler): PlainExtension, defineFilePasteHandlerfunction defineFilePasteHandler(handler: FilePasteHandler): PlainExtension, } from 'prosekit/extensions/file' import type { ImageAttrs } from 'prosekit/extensions/image' import type { Commandtype Command = (state: EditorState, dispatch?: (tr: Transaction) => void, view?: EditorView) => boolean
Commands are functions that take a state and a an optional transaction dispatch function and... - determine whether they apply to this state - if not, return false - if `dispatch` was passed, perform their effect, possibly by passing a transaction to `dispatch` - return true In some cases, the editor view is passed as a third argument.
} from 'prosekit/pm/state'
import type { EditorViewclass EditorView
An editor view manages the DOM structure that represents an editable document. Its state and behavior are determined by its [props](https://prosemirror.net/docs/ref/#view.DirectEditorProps).
} from 'prosekit/pm/view'
async function handleUploadfunction handleUpload(view: EditorView, file: File, pos?: number): Promise<boolean>(viewview: EditorView: EditorViewclass EditorView
An editor view manages the DOM structure that represents an editable document. Its state and behavior are determined by its [props](https://prosemirror.net/docs/ref/#view.DirectEditorProps).
, filefile: File: File, pospos: number | undefined?: number) {
// Upload the file to a remote server and get the URL const urlconst url: string: string = await myUploaderfunction myUploader(file: File): Promise<string>(filefile: File) // Attributes for the image node const attrsconst attrs: ImageAttrs: ImageAttrs = { srcImageAttrs.src?: string | null | undefined: urlconst url: string } // For paste events, `pos` is undefined. The image node will be // inserted at the current text cursor position. // For drop events, `pos` is the drop position. The image node will be // inserted at the drop position. const commandconst command: Command: Commandtype Command = (state: EditorState, dispatch?: (tr: Transaction) => void, view?: EditorView) => boolean
Commands are functions that take a state and a an optional transaction dispatch function and... - determine whether they apply to this state - if not, return false - if `dispatch` was passed, perform their effect, possibly by passing a transaction to `dispatch` - return true In some cases, the editor view is passed as a third argument.
= insertNodefunction insertNode(options: InsertNodeOptions): Command
Returns a command that inserts the given node at the current selection or at the given position.
@public
({ typeInsertNodeOptions.type?: string | NodeType | undefined
The type of the node to insert. Either this or `node` must be provided.
: 'image', attrsInsertNodeOptions.attrs?: Attrs | undefined
When `type` is provided, the attributes of the node to insert.
, posInsertNodeOptions.pos?: number | undefined
The position to insert the node at. By default it will be the anchor position of current selection.
})
return commandconst command: (state: EditorState, dispatch?: (tr: Transaction) => void, view?: EditorView) => boolean(viewview: EditorView.stateEditorView.state: EditorState
The view's current [state](https://prosemirror.net/docs/ref/#state.EditorState).
, viewview: EditorView.dispatchEditorView.dispatch: (tr: Transaction) => void
Dispatch a transaction. Will call [`dispatchTransaction`](https://prosemirror.net/docs/ref/#view.DirectEditorProps.dispatchTransaction) when given, and otherwise defaults to applying the transaction to the current state and calling [`updateState`](https://prosemirror.net/docs/ref/#view.EditorView.updateState) with the result. This method is bound to the view instance, so that it can be easily passed around.
, viewview: EditorView)
} const imagePasteExtensionconst imagePasteExtension: PlainExtension = defineFilePasteHandlerfunction defineFilePasteHandler(handler: FilePasteHandler): PlainExtension(({ viewview: EditorView
The editor view.
, filefile: File
The file that was pasted.
}) => {
if (!filefile: File
The file that was pasted.
.typeBlob.type: string
The **`type`** read-only property of the Blob interface returns the MIME type of the file. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/type)
.startsWithString.startsWith(searchString: string, position?: number): boolean
Returns true if the sequence of elements of searchString converted to a String is the same as the corresponding elements of this object (converted to a String) starting at position. Otherwise returns false.
('image/')) return false
void handleUploadfunction handleUpload(view: EditorView, file: File, pos?: number): Promise<boolean>(viewview: EditorView
The editor view.
, filefile: File
The file that was pasted.
)
return true }) const imageDropExtensionconst imageDropExtension: PlainExtension = defineFileDropHandlerfunction defineFileDropHandler(handler: FileDropHandler): PlainExtension(({ viewview: EditorView
The editor view.
, filefile: File
The file that was dropped.
, pospos: number
The position of the document where the file was dropped.
}) => {
if (!filefile: File
The file that was dropped.
.typeBlob.type: string
The **`type`** read-only property of the Blob interface returns the MIME type of the file. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/type)
.startsWithString.startsWith(searchString: string, position?: number): boolean
Returns true if the sequence of elements of searchString converted to a String is the same as the corresponding elements of this object (converted to a String) starting at position. Otherwise returns false.
('image/')) return false
void handleUploadfunction handleUpload(view: EditorView, file: File, pos?: number): Promise<boolean>(viewview: EditorView
The editor view.
, filefile: File
The file that was dropped.
, pospos: number
The position of the document where the file was dropped.
)
return true })