Multiple file upload
Multiple file upload
Go to top
Also see /react/fileinputarea
React component
Also see /react/examples/singleFileUpload
Single file upload example
Handling events
You can use the onInput event on <FileInputArea> to handle selected files.
Use the multiple prop to allow selecting multiple files at the same time.
<FileInputArea multiple onInput={(e) => { const files = e.currentTarget.files; if (!files || !files.length) return; // add files to selected list... }} />
Area content
<FileInputArea multiple aria-label="Upload file" onInput={...}> <Icon icon={faArrowUpFromBracket} className="bfc-base-2" style={{ marginBottom: 8 }} /> <div> Drag & drop file(s) or{" "} <span className="bf-neutral-link-text">click to upload</span> </div> <div className="bfc-base-2">PDF only</div> </FileInputArea>
List of files
Selected files can be displayed below the input field, with a loading spinner while uploading.
We've added a disabled<Button> here so it will take up the same space as the
remove button later.
<Button small disabled noPadding> <Icon.Spinner /> </Button>{" "} uploading_file.jpg
When the upload completes, swap to a faXMark icon button to remove. Adding
a tooltip for clarity is also a good idea:
<Tooltip content="Remove"> <Button onClick={/* remove file */} variant="flat" small pill noPadding> <Icon icon={faXmark} /> </Button> </Tooltip>{" "} uploaded_file.png
If the upload failed, you can include a red faCircleExclamation icon and a
faRefresh icon button to retry:
<Tooltip content="Remove"> <Button onClick={/* remove file */} variant="flat" small pill noPadding> <Icon icon={faXmark} /> </Button> </Tooltip>{" "} <Tooltip content="Could not upload file"> <Icon icon={faCircleExclamation} className="bfc-alert" marginRight /> </Tooltip> upload_failed.png{" "} <Tooltip content="Retry"> <Button small onClick={/* re-upload */} variant="flat" noPadding pill> <Icon icon={faRefresh} /> </Button> </Tooltip>
Interactive demo
This simulation lets you select some files, fake uploading for ~1s with a 10% chance to fail.
Sandbox
import { useEffect, useState } from "react"; import { faExclamation } from "@fortawesome/free-solid-svg-icons/faExclamation"; import { faRefresh } from "@fortawesome/free-solid-svg-icons/faRefresh"; import { faXmark } from "@fortawesome/free-solid-svg-icons/faXmark"; import { faArrowUpFromBracket } from "@fortawesome/free-solid-svg-icons/faArrowUpFromBracket"; import Button from "@intility/bifrost-react/Button"; import FileInputArea from "@intility/bifrost-react/FileInputArea"; import Grid from "@intility/bifrost-react/Grid"; import Icon from "@intility/bifrost-react/Icon"; import Tooltip from "@intility/bifrost-react/Tooltip"; function SelectedFile({ file, removeFile, }: { file: File; removeFile: (file: File) => void; }) { const [uploading, setUploading] = useState(false); const [failed, setFailed] = useState(false); // fake a http upload, with a 10% chance to fake fail const initiateUpload = () => { setFailed(false); setUploading(true); setTimeout( () => { setUploading(false); if (Math.random() > 0.9) { setFailed(true); } }, Math.random() * 500 + 500, ); }; useEffect(initiateUpload, []); return ( <div> <Tooltip content="Remove" disabled={uploading}> <Button onClick={() => removeFile(file)} variant="flat" small aria-label="Remove file" noPadding pill disabled={uploading} > {uploading ? <Icon.Spinner /> : <Icon icon={faXmark} />} </Button> </Tooltip>{" "} {failed && ( <> <Tooltip content="Could not upload file"> <Icon icon={faExclamation} className="bfc-alert" marginRight /> </Tooltip> </> )} {file.name}{" "} {failed && ( <Tooltip content="Retry"> <Button small onClick={initiateUpload} variant="flat" noPadding pill> <Icon icon={faRefresh} /> </Button> </Tooltip> )} </div> ); } export default function MultipleFileUpload() { const [selectedFiles, setSelectedFiles] = useState<File[]>([]); const inputEventHandler = (e: React.FormEvent<HTMLInputElement>) => { const files = e.currentTarget.files; if (!files || !files.length) return; setSelectedFiles((x) => [ ...x, ...Array.from(files).filter((y) => !x.some((f) => f.name === y.name)), ]); }; return ( <Grid> <FileInputArea multiple onInput={inputEventHandler}> <Icon icon={faArrowUpFromBracket} className="bfc-base-2" style={{ marginBottom: 8 }} /> <div> Drag & drop file(s) or{" "} <span className="bf-neutral-link-text">click to upload</span> </div> <div className="bfc-base-2">PDF only</div> </FileInputArea> {selectedFiles.length > 0 && ( <Grid gap={4}> {selectedFiles.map((file) => ( <SelectedFile key={file.name} file={file} removeFile={(fileToRemove) => setSelectedFiles( selectedFiles.filter((x) => x !== fileToRemove), ) } /> ))} </Grid> )} </Grid> ); }