Preview

Shows the file list. It ships a responsive grid with thumbnails, progress, and cancel/retry/remove—or hand it a render prop and own the markup yourself.

import { Preview } from "uplofile";

Usage

Uploader.tsx
import { Dropzone, Preview, Root, Trigger } from "uplofile";
const upload = async (file: File) => ({ url: URL.createObjectURL(file) });
export function Uploader() {
return (
<Root upload={upload}>
<Dropzone>
<Trigger>Select files</Trigger>
{/* No render prop: the built-in grid has thumbnails, progress, and actions. */}
<Preview />
</Dropzone>
</Root>
);
}

Pass render to skip the default grid and build your own list from the same state:

CustomPreview.tsx
import { Preview } from "uplofile";
// render replaces the default grid entirely; build your own list.
<Preview
render={({ items, actions }) => (
<ul>
{items.map((item) => (
<li key={item.uid}>
{item.name} - {item.status}
<button onClick={() => actions.remove(item.uid)}>Remove</button>
</li>
))}
</ul>
)}
/>;

Failed removals

If onRemove throws or rejects, the item stays (or is restored, in optimistic mode) at status: "done" with error set to the failure message. The built-in grid shows the same error badge and message it uses for a failed upload, and the file stays removable — no render prop or custom handling needed:

Uploader.tsx
import { Dropzone, Preview, Root } from "uplofile";
const upload = async (file: File) => ({ url: URL.createObjectURL(file) });
export function Uploader() {
return (
<Root
upload={upload}
onRemove={async (item, signal) => {
const response = await fetch(`/api/files/${item.id}`, {
method: "DELETE",
signal,
});
if (!response.ok) throw new Error("Delete failed");
}}
>
<Dropzone>
{/* If onRemove throws/rejects, the item stays at status "done" with
error set — Preview shows the same badge/message it uses for a
failed upload, no extra wiring required. */}
<Preview />
</Dropzone>
</Root>
);
}

Render props

Passed to render in place of the built-in grid.

itemsUploadFileItem[]
The current file list.
isLoadingboolean
True while initial is still resolving.
setItems(items | updater) => void
Replace the list directly. An escape hatch, not the usual path.
actionsItemActions
cancel, remove, and retry: the same shape returned by useUplofile().

Props

render(api: PreviewRenderProps) => ReactNode
Replace the built-in grid entirely. See render props below.
classNamestring
Appended to the built-in grid's wrapper. Ignored once render is set.