Skip to content

Editor uploads

When the user drops a file into the timeline or the sidebar, the editor calls onUpload(file). Resolve the promise with a public URL and the editor uses that for all references — playback, rendering, caching.

Signature

typescript
type UploadHandler = (file: File) => Promise<string>;

S3 example

jsx
<VideoEditor
  video={v}
  onUpload={async (file) => {
    const { url, fields } = await fetch('/api/presigned', {
      method: 'POST',
      body: JSON.stringify({ name: file.name, type: file.type }),
    }).then((r) => r.json());

    const body = new FormData();
    Object.entries(fields).forEach(([k, v]) => body.append(k, v));
    body.append('file', file);

    await fetch(url, { method: 'POST', body });
    return `${url}/${fields.key}`;
  }}
/>

Cloudflare R2 / Supabase

jsx
<VideoEditor
  onUpload={async (file) => {
    const form = new FormData();
    form.append('file', file);
    const res = await fetch('/api/upload', { method: 'POST', body: form });
    const { url } = await res.json();
    return url;
  }}
/>

Fallback: object URLs

If you don't pass onUpload, the editor wraps dropped files with URL.createObjectURL() and revokes them on unmount. Great for demos — a dead end for anything persisted.

WARNING

CORS. Whatever URL you return must be reachable with CORS enabled so the editor's renderer can decode it. S3 and R2 both need an explicit GET policy allowing your app origin.

Released under the MIT License.