npx shadcn@latest add https://sdk-components.thesqd.com/r/file-picker.jsonimport { FilePicker } from "@/components/ui/file-picker";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}
/>
);
}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)We find work like this in the Squad library and design from that. Your image is never copied.
| Prop | Type | Default | Description |
|---|---|---|---|
accept | string | string[] | — | Allowed MIME types or extensions — `["image/*"]`, `["application/pdf", ".psd"]`. Joined into the input's `accept` attribute. |
icon | ReactNode | <Images weight="duotone" /> | Glyph rendered in the tile. |
label | ReactNode | "Add" | Caption under the icon. Pass `null` for an icon-only tile. |
multiple | boolean | false | Allow picking more than one file at a time. |
maxFiles | number | — | Cap on how many files the picker holds. Extra files fire `onFileReject`. |
maxSize | number | — | Per-file size cap in bytes. Larger files fire `onFileReject`. |
value / defaultValue | File[] | — | 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`. |
preview | boolean | true | Render thumbnails of picked files beside the tile, each with a remove button. |
hideWhenFull | boolean | true | Hide the tile once `maxFiles` is reached. Set false to keep it visible but disabled. |
disabled | boolean | — | Dim the tile and block the picker. |
tileClassName | string | — | Classes for the tile itself. `className` styles the row that holds the tile and thumbnails. |