Siteplane UI

File Upload

Pro

Drop or browse files and follow each upload’s progress.

Markdown
or drag and drop

PDF, JPG or CSV up to 10 MB.

  • Project-brief.pdf

    1.2 MBComplete

    x
    100%
  • Dashboard-draft.jpg

    720 KBUploading…

    x
    40%
  • Q3-export.csv

    310 KBConnection lost

Pro

This example installs with a Siteplane UI Pro license key.

Get a license on the Pro page.

pnpm dlx shadcn@4.18.0 add @siteplane-pro/file-upload-demo

This Pattern is part of Siteplane UI Pro, and its source comes with a Pro license. Its previews are free to view and try.

Installation

pnpm dlx shadcn@4.18.0 add @siteplane-pro/file-upload
Pro

Installs with a Siteplane UI Pro license key. Complete the one-time Pro setup first.

Get a license on the Pro page.

Usage

import {
  FileUpload,
  type UploadFile,
} from "@/siteplane/components/file-upload";

const files: UploadFile[] = [
  { id: "brief", name: "Brief.pdf", sizeLabel: "1.2 MB", status: "complete" },
];

<FileUpload
  accept="application/pdf,image/*"
  description="PDF or image, up to 10 MB."
  files={files}
  maxSize={10 * 1024 * 1024}
  onFilesSelected={(selected) => {
    // Start your own uploads, then update `files` as they progress.
    console.log(selected);
  }}
/>;

Composition

FileUpload renders every part itself. You supply the files, their status and the handlers.

FileUpload
├── Dropzone (Card)
│   ├── Icon
│   ├── Browse button and hidden file input
│   └── Description
├── Rejection messages (live region)
└── File list
    └── Row (Card)
        ├── FileTypeIcon
        ├── Name, size and status
        ├── Progress
        ├── Try again (failed rows)
        └── Remove button

Progress

Each row shows a progress bar by default. Set variant="fill" to show progress as a tint that fills the row from its start edge, with the percentage in the status line; the tint fades out once the upload completes or fails. The bar stays available to assistive technology in both variants.

Report the real progress of your upload request in files. The examples on this page use a timer instead of a request.

or drag and drop

Add files to share with your team.

  • Annual-report.pdf

    4.8 MB62%

    x
    62%
  • Team-photo.png

    2.1 MB18%

    x
    18%
  • Meeting-notes.docx

    86 KB100%

    x
    100%
Pro

This example installs with a Siteplane UI Pro license key.

Get a license on the Pro page.

pnpm dlx shadcn@4.18.0 add @siteplane-pro/file-upload-progress-fill-example

Compact dropzone

Set compact for a shorter dropzone without the icon. It is made for a row where the zone sits beside an avatar or a label. With multiple={false} only the first file of a selection or drop counts, which suits a single profile photo, and the dropzone lists any other file as rejected. This example shows the chosen image as the avatar instead of listing a row.

ME
or drag and drop

PNG, JPG or GIF up to 2 MB.

    Pro

    This example installs with a Siteplane UI Pro license key.

    Get a license on the Pro page.

    pnpm dlx shadcn@4.18.0 add @siteplane-pro/file-upload-compact-example

    Accepted files and size limit

    accept takes MIME types, wildcards such as image/* and extensions such as .pdf, like a native file input, and also filters the browser’s file dialog. maxSize is a limit per file in bytes. A file that fails either check never reaches onFilesSelected. The dropzone lists it below with the reason, and onRejected receives it. State the limits in description so people see them before they choose files.

    Choose a file that is not a PNG or JPG, or larger than 2 MB, to see the messages.

    or drag and drop

    PNG or JPG, up to 2 MB each.

      Pro

      This example installs with a Siteplane UI Pro license key.

      Get a license on the Pro page.

      pnpm dlx shadcn@4.18.0 add @siteplane-pro/file-upload-restrictions-example

      Surface

      The dropzone and the rows use the inset surface by default, so they press into the surface that holds them, such as a Card, a Dialog or a Sheet. Set surface="raised" when the upload sits directly on the page background and should lift like a Card. A row whose upload failed keeps its error surface with either value.

      or drag and drop

      Contracts and terms, up to 10 MB.

      • Service-contract.pdf

        640 KBUploading…

        x
        55%
      • Terms-of-service.docx

        92 KBComplete

        x
        100%
      Pro

      This example installs with a Siteplane UI Pro license key.

      Get a license on the Pro page.

      pnpm dlx shadcn@4.18.0 add @siteplane-pro/file-upload-raised-example

      Disabled

      Set disabled to switch the upload off, for example for an archived project. The dropzone keeps its surface while its icon and text dim, and its browse button, drops, Try again and remove do nothing. Rows already in the list stay visible.

      or drag and drop

      Uploads are paused while this project is archived.

        Pro

        This example installs with a Siteplane UI Pro license key.

        Get a license on the Pro page.

        pnpm dlx shadcn@4.18.0 add @siteplane-pro/file-upload-disabled-example

        API reference

        FileUpload

        Component properties
        PropTypeDefaultDescription
        filesreadonly UploadFile[][]Rows listed under the dropzone, in the order you pass them. The application owns the list, each status and each progress value.
        onFilesSelected(files: File[]) => voidunsetCalled after a selection or a drop with the files that pass accept and maxSize; while multiple is off, only the first file can pass. Start the uploads here.
        onRejected(files: FileRejection[]) => voidunsetCalled with the files that were not taken. A file's reason is type when accept excludes it, size when it is over maxSize and count when it is a surplus file while multiple is off. The dropzone also lists them below itself.
        onRemove(id: string) => voidunsetShows a remove button on every row and receives the row’s id. Stop the upload and update files.
        onRetry(id: string) => voidunsetShows Try again on a failed row and receives the row’s id.
        acceptstringunsetComma-separated MIME types, type/* wildcards or .extensions, as for a native file input.
        maxSizenumberunsetLargest accepted file size in bytes.
        multiplebooleantrueAccept several files at once. When false, only the first file of a selection or drop is taken, and the others are rejected with the reason count.
        disabledbooleanfalseSwitches off the dropzone, Try again and remove.
        descriptionReactNodeunsetHint under the dropzone text, such as the allowed types and size.
        variantbar | fillbarProgress as a bar in each row or as a fill behind it.
        compactbooleanfalseShorter dropzone without the icon, for a row beside an avatar or a label.
        surfaceinset | raisedinsetCard surface of the dropzone and the rows. A failed row keeps its error surface.
        labelsPartial<FileUploadLabels>English textEvery visible and spoken string; see the keys below.

        FileUploadProps extends native div props except onSelect, so className, id and aria-* reach the root. The component is not a form field: it submits nothing and has no name or value. A FileRejection holds the file and its reason.

        The keys of labels, each with its English default, are select (Click to upload), drop (or drag and drop), uploading (Uploading…), complete (Complete), failed (Upload failed), retry (Try again), remove (Remove), files (Files, the name of the list), rejectedType (File type not accepted), rejectedSize (File exceeds size limit) and rejectedCount (Only one file can be uploaded). remove and retry are followed by the file name in each button’s accessible name, and each rejection message starts with the file name. With variant="fill", a row shows its percentage in place of uploading and complete.

        UploadFile

        Component properties
        PropTypeDefaultDescription
        idstringrequiredStable key of the row, passed to onRemove and onRetry.
        namestringrequiredFile name. Its extension chooses the FileTypeIcon, and it names the progress bar.
        sizeLabelstringrequiredSize as text, formatted by the application, such as 720 KB.
        statusuploading | complete | errorrequiredState of the row. A complete row shows 100%.
        progressnumber0Percent from 0 to 100 while uploading. Values outside the range are clamped.
        errorstringUpload failedMessage of a failed row, in place of labels.failed.

        Usage notes

        FileUpload does not upload anything. Start the request in onFilesSelected, report progress and the final status through files, and own cancellation, retries and server-side validation. Removing a row only calls onRemove; abort the request there.

        accept and maxSize help the person choosing files. They are not a security check, so validate type and size again on the server.

        Give every row a stable id: rows animate in and out by key. Format sizeLabel and error messages for your locale and pass translated strings through labels.

        The dropzone is operated through its browse button; the hidden file input is not a tab stop. Rejection messages appear below the dropzone in a polite live region. After a row is removed, focus moves to a neighboring row or back to the browse button, and after Try again it moves to the row’s remove button, or to the browse button when the row has none. With reduced motion, rows, rejection messages and the fill change without animation.

        The file rows use File Type Icon.