@uploadjoy/react

The @uploadjoy/react package contains the hooks and components for building upload UIs with React.

useInput

The useInput hook is a React hook that provides a helpers and configuration for building a file input component.

Basic Usage

Assuming you have a file router set up, you can use the useInput hook to build a file input component.

import { useInput } from "@uploadjoy/react/hooks";
import type { OurFileRouter } from "@/server/uploadjoy";

export function MyComponent() {
  const { getInputProps, openFileDialog, upload } = useInput<OurFileRouter>({
    endpoint: "imageUploader",
    clientCallbacks: {
      onUploadSuccess: (ctx) => {
        console.log(ctx);
      },
    },
  });

  return (
    <>
      <input {...getInputProps()} />
      <button
        onClick={openFileDialog}
        className="m-2 rounded-md bg-indigo-700 p-2"
      >
        Pick Files
      </button>
      <button
        onClick={() => upload()}
        className="m-2 rounded-md bg-slate-700 p-2"
      >
        Upload
      </button>
    </>
  );
}

Configuration

The useInput hook accepts a configuration object with the following properties:

  • Name
    disabled
    Type
    boolean (optional)
    Description

    Sets the disabled attribute on the input element.

  • Name
    onFileDialogCancel
    Type
    () => void; (optional)
    Description

    Function to call when the file dialog is cancelled.

  • Name
    onFileDialogOpen
    Type
    () => void; (optional)
    Description

    Function to call when the file dialog is opened.

  • Name
    onFileDialogError
    Type
    (error: Error) => void; (optional)
    Description

    Function to call when the file dialog encounters an error.

  • Name
    endpoint
    Type
    string (required)
    Description

    The name of a route configured in the file router to use for the upload. If you correctly provided the type of your file router to the generic type parameter of the useInput hook, this will be type checked against the routes you configured.

  • Name
    clientCallbacks
    Type
    ClientCallbacks (optional)
    Description

    An object containing callbacks to be called on the client. See the type definitions below for more information.

    type ClientOnUploadCallback = (input: {
      file: File;
      access: "private" | "public";
    }) => Promise<void> | void;
    
    type ClientOnUploadFailureCallback = (input: {
      file: File;
      access: "private" | "public";
    }) => Promise<void> | void;
    
    type ClientOnUploadProgressCallback = (input: {
      file: File;
      access: "private" | "public";
      uploadProgress: Pick<ProgressEvent, "loaded" | "total">;
    }) => Promise<void> | void;
    
    type ClientCallbacks = {
      onUpload?: ClientOnUploadCallback;
      onUploadFailure?: ClientOnUploadFailureCallback;
      onUploadProgress?: ClientOnUploadProgressCallback;
    };
    

Returns

The useInput hook returns an object with the following properties:

  • Name
    getInputProps
    Type
    function
    Description

    Returns an object containing the props to be spread on the input element.

  • Name
    openFileDialog
    Type
    () => void
    Description

    Opens the file dialog.

  • Name
    upload
    Type
    () => Promise<void>
    Description

    Uploads the selected files.

  • Name
    reset
    Type
    () => void
    Description

    Resets the input element.

  • Name
    readyToUpload
    Type
    boolean
    Description

    Whether or not the input element is ready to upload files based on if presigned URLs have been fetched.

  • Name
    isUploading
    Type
    boolean
    Description

    Whether or not files are being uploaded.

useDropzone

The useDropzone hook is a React hook that provides a helpers and configuration for building a dropzone component.

Basic Usage

Assuming you have a file router set up, you can use the useInput hook to build a file input component.

import type { OurFileRouter } from "@/server/uploadjoy";
import { useDropzone } from "@uploadjoy/react/hooks";

export const Dropzone = () => {
  const { getInputProps, openFileDialog, upload, getDropzoneRootProps } =
    useDropzone<OurFileRouter>({
      endpoint: "imageUploader",
      clientCallbacks: {
        onUploadSuccess: (ctx) => {
          console.log("onUploadSuccess", ctx);
        },
      },
    });

  return (
    <div>
      <h2 className="mb-3 text-xl font-medium">Dropzone Component</h2>
      <div
        // Spread the props on the root element of your dropzone component
        {...getDropzoneRootProps()}
        className="mb-2 flex h-[200px] w-[200px] flex-col items-center
        justify-center rounded-md border border-dashed border-indigo-500 hover:cursor-pointer
        focus:border-white"
        onClick={() => openFileDialog()}
      >
        <p className="text-slate-500">Drag and Drop here!</p>
        <p className="text-sm text-slate-500">or click to open file dialog</p>
        {/* Spread the props for the file input component */}
        <input {...getInputProps()} />
      </div>
      <div className="flex gap-4">
        <button
          onClick={() => upload()}
          className="w-fit rounded-md bg-slate-700 p-2"
        >
          Upload
        </button>
      </div>
    </div>
  );
};

Configuration

The useDropzone hook accepts a configuration object with the following properties:

  • Name
    disabled
    Type
    boolean (optional)
    Description

    Sets the disabled attribute on the input element.

  • Name
    onFileDialogCancel
    Type
    () => void; (optional)
    Description

    Function to call when the file dialog is cancelled.

  • Name
    onFileDialogOpen
    Type
    () => void; (optional)
    Description

    Function to call when the file dialog is opened.

  • Name
    onFileDialogError
    Type
    (error: Error) => void; (optional)
    Description

    Function to call when the file dialog encounters an error.

  • Name
    onDragEnter
    Type
    () => void; (optional)
    Description

    Function to call when the dragenter event is fired on the dropzone.

  • Name
    onDragLeave
    Type
    () => void; (optional)
    Description

    Function to call when the dragleave event is fired on the dropzone.

  • Name
    onDragOver
    Type
    () => void; (optional)
    Description

    Function to call when the dragover event is fired on the dropzone.

  • Name
    onDrop
    Type
    () => void; (optional)
    Description

    Function to call when the drop event is fired on the dropzone.

  • Name
    endpoint
    Type
    string (required)
    Description

    The name of a route configured in the file router to use for the upload. If you correctly provided the type of your file router to the generic type parameter of the useInput hook, this will be type checked against the routes you configured.

  • Name
    clientCallbacks
    Type
    ClientCallbacks (optional)
    Description

    An object containing callbacks to be called on the client. See the type definitions below for more information.

    type ClientOnUploadCallback = (input: {
      file: File;
      access: "private" | "public";
    }) => Promise<void> | void;
    
    type ClientOnUploadFailureCallback = (input: {
      file: File;
      access: "private" | "public";
    }) => Promise<void> | void;
    
    type ClientOnUploadProgressCallback = (input: {
      file: File;
      access: "private" | "public";
      uploadProgress: Pick<ProgressEvent, "loaded" | "total">;
    }) => Promise<void> | void;
    
    type ClientCallbacks = {
      onUpload?: ClientOnUploadCallback;
      onUploadFailure?: ClientOnUploadFailureCallback;
      onUploadProgress?: ClientOnUploadProgressCallback;
    };
    

Returns

The useDropzone hook returns an object with the following properties:

  • Name
    getInputProps
    Type
    function
    Description

    Returns an object containing the props to be spread on the file input element.

  • Name
    getDropzoneRootProps
    Type
    function
    Description

    Returns an object containing the props to be spread on the root element of your dropzone component.

  • Name
    openFileDialog
    Type
    () => void
    Description

    Opens the file dialog.

  • Name
    upload
    Type
    () => Promise<void>
    Description

    Uploads the selected files.

  • Name
    reset
    Type
    () => void
    Description

    Resets the input element.

  • Name
    readyToUpload
    Type
    boolean
    Description

    Whether or not the input element is ready to upload files based on if presigned URLs have been fetched.

  • Name
    isUploading
    Type
    boolean
    Description

    Whether or not files are being uploaded.

useUploadjoy

If you want to build a more custom upload component, @uploadjoy/react exposes a useUploadjoy hook that provides a lot of the same functionality as the useInput and useDropzone hooks.

Basic Usage

Assuming you have a file router set up, you can generate the useUploadjoy hook for your file router and use it to build a file input component.

import { generateReactHelpers } from "@uploadjoy/react/hooks";
import type { OurFileRouter } from "@/server/uploadjoy";
import { useState } from "react";
import { PresignedUrlRequestResponse } from "@uploadjoy/core/client";

const { useUploadjoy } = generateReactHelpers<OurFileRouter>();

export const CustomComponentWithHelpers = () => {
  const [files, setFiles] = useState<File[]>([]);
  const [presignedUrls, setPresignedUrls] = useState<
    PresignedUrlRequestResponse | undefined
  >(undefined);

  const {
    isUploading,
    fetchPresignedUrls,
    startUpload,
    permittedFileInfo,
    getMimeTypesFromConfig,
  } = useUploadjoy({ endpoint: "imageUploader" });

  return (
    <div>
      <h2 className="mb-3 text-xl font-medium">
        Custom Component with Helpers
      </h2>
      {permittedFileInfo && (
        <div>
          <input
            type="file"
            onChange={async (e) => {
              setFiles(Array.from(e.target.files ?? []));
              const presignedUrls = await fetchPresignedUrls({
                files: Array.from(e.target.files ?? []),
              });
              setPresignedUrls(presignedUrls);
            }}
            accept={getMimeTypesFromConfig(permittedFileInfo.config).join(",")}
          />
          {presignedUrls && (
            <button
              onClick={() =>
                startUpload({
                  presignedUrls,
                  files,
                  clientCallbacks: {
                    onUploadSuccess: (ctx) => {
                      console.log("onUploadSuccess", ctx);
                    },
                  },
                })
              }
              disabled={isUploading}
            >
              {isUploading ? "Uploading..." : "Upload"}
            </button>
          )}
        </div>
      )}
    </div>
  );
};

We import generateReactHelpers from @uploadjoy/react/hooks and provide our file router type as a generic type parameter. This will type check the useUploadjoy hook against the routes we configured in our file router.

Configuration

The useUploadjoy hook accepts an object with the following properties:

  • Name
    endpoint
    Type
    string
    Description

    File router endpoint to use for the upload.

Returns

The useUploadjoy hook returns an object with the following properties:

  • Name
    fetchPresignedUrls
    Type
    function
    Description

    A function you can call to fetch presigned URLs for the files you wish to upload.

  • Name
    startUpload
    Type
    function
    Description

    A function you can call to start uploading files.

  • Name
    isUploading
    Type
    boolean
    Description

    Whether or not files are being uploaded.

  • Name
    isFetchingPresignedUrls
    Type
    boolean
    Description

    Whether or not presigned URLs are being fetched.

  • Name
    permittedFileInfo
    Type
    PermittedFileInfo
    Description

    Information about the permitted files and config based on the configured route.

    See the source for more information.

  • Name
    getMimeTypesFromConfig
    Type
    function
    Description

    A helper function you can call to get the mime types from the router config in permittedFileInfo.