Skip to content

shadcn.io is an independent project built on shadcn/ui

Free

File Upload with List Input for React

An Upload Files field that accepts several files and then lists each name, its size in KB, and a remove button.

An Upload Files label and a file field that accepts more than one file. After a pick, each row shows a file icon, the name, the size in KB, and a remove button.

Use it when people attach a few files before they submit. A dashed drop zone that keeps the list is File Upload. In React, Base UI does not remove the input's file when the row goes away.

Preview

Preview width

Installation

Sign in to get your install command
Free with an account. It carries your token, so the CLI installs everything in one go.
Use email insteadNo credit card

Anatomy

Input anatomy: input, placeholder, value, caret

Usage

<Field className="w-full max-w-sm">
  <FieldLabel htmlFor="file-upload">Upload Files</FieldLabel>
  <Input
    className="bg-background"
    id="file-upload"
    multiple
    onChange={handleFileChange}
    type="file"
  />
  {files.length > 0 ? (
    <ul className="flex flex-col gap-2">
      {files.map((file, index) => (
        <li
          className="flex items-center justify-between gap-2 rounded-md border p-2"
          key={`${file.name}-${file.lastModified}`}
        >
          <div className="flex min-w-0 items-center gap-2">
            <FileTextIcon
              aria-hidden="true"
              className="size-4 shrink-0 text-muted-foreground"
            />
            <span className="truncate text-sm">{file.name}</span>
            <span className="shrink-0 text-muted-foreground text-xs">
              ({(file.size / 1024).toFixed(1)} KB)
            </span>
          </div>
          <Button
            aria-label={`Remove ${file.name}`}
            data-index={index}
            onClick={handleRemove}
            size="icon-xs"
{/* The rest of the file is under Installation. */}

FAQ

How does the field accept several files?

multiple on the file input lets the picker select more than one. Each time the selection changes, the chosen files are copied from the input into a list kept in state, which renders the rows.

What does each row show?

A FileTextIcon, the file name, truncated when it's long, and the size in kilobytes with one decimal, from the file's size divided by 1024. The rows are a list with a border and rounded corners.

How does the remove button work?

It's a ghost Button at size icon-xs with an XIcon. It carries its row's index in data-index and removes that file from the list. Its aria-label names the file, such as Remove report.pdf.

Does removing a row change what the input holds?

No. The list is the example's own state; the browser's file input still holds the files from the last pick. Submit the list from state, for example with FormData, rather than the input itself.

How do I limit the file types?

Add accept to the input, such as accept="image/*" or accept=".pdf,.docx". The picker then filters to those types; check them again on the server.

How is Upload Files tied to the field?

Clicking the label focuses the field, and screen readers announce it with the field. FieldLabel sets htmlFor to file-upload, the input's id.

API Reference

Field

Sets htmlFor="file-upload". The rest is on the Field page.

Input

Sets id="file-upload", multiple, onChange={handleFileChange} and type="file". The rest is on the Input page.

Button

Sets aria-label, Remove, file, name, data-index={index} and onClick={handleRemove}. The rest is on the Button page.