FileUpload
Drag-and-drop file upload zone with click-to-browse and uploaded file list.
Use and inspectUse this as a presentational interface around your own submit, stream, or state handlers. Reset preview only remounts the local example; it does not send a request or connect to a model.Next: inspect the source and wire its callback to a bounded backend action.
FileUploadDrag-and-drop file upload zone with click-to-browse and uploaded file list.
"use client";
import { useState, useRef } from "react";
type FileUploadProps = {
accept?: string;
multiple?: boolean;
onFiles?: (f: File[]) => void;
};
export function FileUpload({ accept, multiple = false, onFiles }: FileUploadProps) {
const [files, setFiles] = useState<File[]>([]);
const [dragging, setDragging] = useState(false);
const inputRef = useRef<HTMLInputElement>(null);
function handleFiles(incoming: FileList | null) {
if (!incoming) return;
const arr = Array.from(incoming);
setFiles((prev) => [...prev, ...arr]);
onFiles?.(arr);
}
return (
<div className="pk-file-upload">
<div
className={`pk-file-zone${dragging ? " pk-file-zone--drag" : ""}`}
onDragOver={(e) => { e.preventDefault(); setDragging(true); }}
onDragLeave={() => setDragging(false)}
onDrop={(e) => { e.preventDefault(); setDragging(false); handleFiles(e.dataTransfer.files); }}
onClick={() => inputRef.current?.click()}
role="button"
tabIndex={0}
onKeyDown={(e) => e.key === "Enter" && inputRef.current?.click()}
>
<span className="pk-file-zone-icon">↑</span>
<span className="pk-file-zone-text">Drop files or click to browse</span>
<input
ref={inputRef}
type="file"
accept={accept}
multiple={multiple}
style={{ display: "none" }}
onChange={(e) => handleFiles(e.target.files)}
/>
</div>
{files.length > 0 && (
<ul className="pk-file-list">
{files.map((f, i) => (
<li key={i} className="pk-file-item">
<span className="pk-file-item-icon">📄</span>
<span className="pk-file-item-name">{f.name}</span>
</li>
))}
</ul>
)}
</div>
);
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
accept | string | — | MIME types or file extensions to accept |
multiple | boolean | false | Allow multiple file selection |
onFiles | (f: File[]) => void | — | Called when files are added |