Silo Docs
React

React

Typed React hooks for uploads, staged flows, and progress events.

@silo-storage/sdk-react is the client-side package for Silo uploads.

It is built around a factory, createSiloReact, which binds your upload endpoint once and returns typed hooks and headless components.

Create the React helpers

import type { AppFileRouter } from "@/app/api/upload/core";

import { createSiloReact } from "@silo-storage/sdk-react";

export const {
  useUpload,
  useStagedUpload,
  UploadButton,
  UploadDropzone,
  SiloRouterConfigProvider,
} = createSiloReact<AppFileRouter>({
  endpoint: "/api/upload",
});

useUpload

useUpload is the main hook for direct uploads.

It supports callbacks such as:

  • onUploadBegin
  • onUploadProgress
  • onComplete
  • onError
  • onUploadAborted
  • onFileDialogCancel

Upload one file:

const upload = useUpload({ endpoint: "imageUploader" });

await upload.uploadFile(file, {
  input: { albumId: "abc" },
});

Upload many files:

await upload.uploadFiles(files, {
  input: { albumId: "abc" },
  concurrency: 4,
});

If you want a single signed upload request instead of the default resumable TUS flow, pass uploadMethod: "put":

await upload.uploadFile(file, {
  input: { albumId: "abc" },
  uploadMethod: "put",
});

Multi-file callback behavior

When you call upload.uploadFiles(files, ...), each file uploads and completes independently.

  • Server-side onUploadComplete(...) runs once per file
  • Client-side onComplete(completions) runs once after all files finish
  • The completions array contains one entry per uploaded file

If you upload 3 files successfully, your route's onUploadComplete(...) handler runs 3 times, and your React onComplete(...) callback runs once with 3 completion objects.

Open a file picker and upload immediately:

await upload.beginUpload({
  multiple: true,
  input: { albumId: "abc" },
});

If your server route uses a function-based .expects(...) resolver, the client cannot infer a stable picker filter from router config alone.

In that case, pass accept to useUpload(...), useStagedUpload(...), UploadButton, or UploadDropzone if you want to control the file picker's accepted types.

useStagedUpload

useStagedUpload is better for chat-style or draft-style interfaces where file selection and upload happen in separate steps.

You should use this when you want the user to select files first, but upload them later. (e.g in a chat or messaging interface)

const staged = useStagedUpload({
  endpoint: "imageUploader",
  onUploadProgress: (event) => {
    console.log(event.aggregatePercent);
  },
});

await staged.openFilePicker();
await staged.upload();

It returns staged state and actions such as:

  • files
  • openFilePicker
  • removeFile
  • clearFiles
  • upload
  • isUploading
  • uploadProgress

Router config hydration

createSiloReact(...) accepts optional routerConfig. You can also provide that later with SiloRouterConfigProvider if your server renders or fetches route config separately.

That router config only contains statically known route expectations. If a route's .expects(...) value is a function, the React SDK cannot derive a picker accept value from extractRouterConfig(...), so you should provide accept explicitly on the hook or component you use to open the picker.

If you want a concrete UI example in this repo, see the existing SDK Demo.

API reference

For generated hook and factory type tables, see API Reference.

On this page