File picker

A button-sized tile for attaching files inline in a form.

Installation
$Terminal
npx shadcn@latest add https://sdk-components.thesqd.com/r/file-picker.json
Usage
Import from the master file and pass the accepted types, icon, and label.
TSImport
import { FilePicker } from "@/components/ui/file-picker";
TSExample
import * as React from "react";
import { Images as ImagesIcon } from "@phosphor-icons/react/ssr";
import { FilePicker } from "@/components/ui/file-picker";

export function Example() {
  const [files, setFiles] = React.useState<File[]>([]);

  return (
    <FilePicker
      multiple
      maxFiles={3}
      accept={["image/*"]}
      icon={<ImagesIcon weight="duotone" className="size-5" />}
      label="Add"
      value={files}
      onValueChange={setFiles}
    />
  );
}
Composition
Anatomy of the FilePicker primitive.
FilePicker                       (single component — pass everything as props)
├── accept={["image/*"]}         (MIME types or extensions; string or string[])
├── icon={<PhosphorIcon />}      (tile glyph — defaults to a duotone image icon)
├── label="Add"                  (tile caption; pass null for icon-only)
├── maxFiles / multiple          (how many files the picker accepts)
├── value / onValueChange        (controlled File[]; omit for uncontrolled)
├── preview                      (thumbnails of picked files, default true)
└── hideWhenFull                 (hide the tile at maxFiles, default true)
Default
A dotted card-surface tile at the input height, picking up to three images. Picked files appear as thumbnails beside it.
In a field
Paired with a FieldLabel — the shape it takes in a real form, where it sits under the label and caption.

We find work like this in the Squad library and design from that. Your image is never copied.

Custom types, icon, and label
`accept` takes MIME types or extensions; `icon` and `label` set what the tile shows.
Icon only
Pass `label={null}` to drop the caption and center the icon.
Single file
With `maxFiles={1}` the tile hides once a file is picked, leaving just the thumbnail. Set `hideWhenFull={false}` to keep it visible but disabled.
API Reference
Props exposed by the FilePicker component.
PropTypeDefaultDescription
acceptstring | string[]—Allowed MIME types or extensions — `["image/*"]`, `["application/pdf", ".psd"]`. Joined into the input's `accept` attribute.
iconReactNode<Images weight="duotone" />Glyph rendered in the tile.
labelReactNode"Add"Caption under the icon. Pass `null` for an icon-only tile.
multiplebooleanfalseAllow picking more than one file at a time.
maxFilesnumber—Cap on how many files the picker holds. Extra files fire `onFileReject`.
maxSizenumber—Per-file size cap in bytes. Larger files fire `onFileReject`.
value / defaultValueFile[]—Controlled / uncontrolled list of picked files. Pass `value={[]}` if the files live in your own state as object URLs.
onValueChange(files: File[]) => void—Fires whenever the list changes (pick or remove).
onFileReject(file: File, message: string) => void—Called for each file rejected by `maxSize` or `maxFiles`.
previewbooleantrueRender thumbnails of picked files beside the tile, each with a remove button.
hideWhenFullbooleantrueHide the tile once `maxFiles` is reached. Set false to keep it visible but disabled.
disabledboolean—Dim the tile and block the picker.
tileClassNamestring—Classes for the tile itself. `className` styles the row that holds the tile and thumbnails.