Portive

Slate Cloud

Uploading Files

In Getting Started, we added support for uploading by pasting files into or dropping files onto the editor. We did this by adding editor.cloud.handlePaste and editor.cloud.handleDrop to the Editable component.

<Editable
  renderElement={renderElement}
  onPaste={editor.cloud.handlePaste}
  onDrop={editor.cloud.handleDrop}
/>

Sometimes, you want to upload files using another method like opening a File picker or working with a File object.

Slate Cloud has two functions for uploading files:

Uploading

Upload using a File Input

To upload from an <input type="file" /> element, add the editor.cloud.onInputFileChangeHandler to the onChange attribute.

JavaScript
import { useState } from "react"
import { createEditor } from "slate"
import { withHistory } from "slate-history"
import { Editable, Slate, withReact } from "slate-react"
import { withCloud } from "slate-cloud"
import { CloudComponents } from "slate-cloud/cloud-components"
const renderElement = CloudComponents.withRenderElement((props) => {
const { element } = props
if (element.type === "paragraph") {
return <p {...props.attributes}>{props.children}</p>
}
throw new Error(`Unhandled element type ${element.type}`)
})
export default function Page() {
const [editor] = useState(() => {
const basicEditor = withHistory(withReact(createEditor()))
const cloudEditor = withCloud(basicEditor, {
apiKey: "MY_API_KEY",
})
CloudComponents.withEditor(cloudEditor)
return cloudEditor
})
return (
<Slate
editor={editor}
value={[{ type: "paragraph", children: [{ text: "Hello World" }] }]}
>
<input
type="file"
onChange={editor.cloud.handleInputFileChange}
multiple
/>
<Editable
renderElement={renderElement}
onPaste={editor.cloud.handlePaste}
onDrop={editor.cloud.handleDrop}
/>
</Slate>
)
}

When the user clicks the <input type="file" /> button, it opens a file picker, and when files are picked the upload process begins.

Upload using File Object

To programmatically upload a file from a File object, use the editor.cloud.uploadFile method and pass a File object as the first argument.

Internally, the handlePaste, handleDrop and handleInputFileChange methods all use the editor.cloud.uploadFile method.

A good use case for this is if you programmatically generate File objects, for example converting a Canvas to an png, and then you want to upload it.

JavaScript
// ✅ import `useCallback` for use later
import { useCallback, useState } from "react"
import { createEditor } from "slate"
import { withHistory } from "slate-history"
import { Editable, Slate, withReact } from "slate-react"
import { withCloud } from "slate-cloud"
import { CloudComponents } from "slate-cloud/cloud-components"
const renderElement = CloudComponents.withRenderElement((props) => {
const { element } = props
if (element.type === "paragraph") {
return <p {...props.attributes}>{props.children}</p>
}
throw new Error(`Unhandled element type ${element.type}`)
})
export default function Page() {
const [editor] = useState(() => {
const basicEditor = withHistory(withReact(createEditor()))
const cloudEditor = withCloud(basicEditor, {
apiKey: "MY_API_KEY",
})
CloudComponents.withEditor(cloudEditor)
return cloudEditor
})
// ✅ This callback goes through each file and uploads it
const upload = useCallback(
(e) => {
const files = e.target.files
if (files == null || files.length === 0) return
for (const file of files) {
editor.cloud.uploadFile(file)
}
},
[editor]
)
return (
<Slate
editor={editor}
value={[{ type: "paragraph", children: [{ text: "Hello World" }] }]}
>
{/* ✅ Add `upload` method as `onChange` handler */}
<input type="file" onChange={upload} multiple />
<Editable
renderElement={renderElement}
onPaste={editor.cloud.handlePaste}
onDrop={editor.cloud.handleDrop}
/>
</Slate>
)
}