FileUpload
FileUpload is an advanced uploader with dragdrop support, multi file uploads, auto uploading, progress tracking and validations.
No file chosen
basic-demo
Usage#
import { FileUpload } from '@primereact/ui/fileupload';<FileUpload></FileUpload>Examples#
Auto#
When auto property is enabled, a file gets uploaded instantly after selection.
auto-demo
'use client';
import { Plus } from '@primeicons/react/plus';
import { Times } from '@primeicons/react/times';
import { toast } from '@primereact/headless/toaster';
import { FileUploadRootInstance } from '@primereact/types/shared/fileupload';
import { ToasterRegionInstance, ToastType } from '@primereact/types/shared/toaster';
import { Button } from '@primereact/ui/button';
import { FileUpload } from '@primereact/ui/fileupload';
import { Message } from '@primereact/ui/message';
import { Toast } from '@primereact/ui/toast';
import { Toaster } from '@primereact/ui/toaster';
export default function AutoDemo() {
const onUpload = () => {
toast({
title: 'Success',
description: 'File Uploaded',
group: 'auto-demo'
});
};
return (
<div className="flex justify-center">
<FileUpload.Root name="demo[]" url="/api/upload" auto accept="image/*" maxFileSize={1000000} onUpload={onUpload}>
{(instance: FileUploadRootInstance) => {
return (
<>
{instance.state.messages &&
instance.state.messages.length > 0 &&
instance.state.messages.map((msg, i) => (
<Message.Root key={i} severity="error" className="mb-2">
<Message.Content>
<Message.Text>{msg}</Message.Text>
</Message.Content>
</Message.Root>
))}
<div className="flex flex-wrap items-center gap-3">
<Button onClick={instance.choose}>
<Plus />
Browse
</Button>
</div>
</>
);
}}
</FileUpload.Root>
<Toaster.Root position="top-right" group="auto-demo">
<Toaster.Portal>
<Toaster.Region>
{({ toaster }: ToasterRegionInstance) =>
toaster?.toasts.map((toast: ToastType) => (
<Toast.Root key={toast.id} toast={toast}>
<div className="grid grid-cols-[auto_1fr] items-start gap-3">
<Toast.Icon className="[&>svg]:size-3.5 mt-1 " />
<div>
<Toast.Title />
<Toast.Description className="mt-1" />
<Toast.Action as={Button} size="small" className="mt-3" />
</div>
</div>
<Toast.Close
as={Button}
iconOnly
severity={'secondary'}
variant="text"
size="small"
className={'absolute top-2 right-2'}
>
<Times />
</Toast.Close>
</Toast.Root>
))
}
</Toaster.Region>
</Toaster.Portal>
</Toaster.Root>
</div>
);
}
Advanced#
Advanced uploader provides dragdrop support, multi file uploads, auto uploading, progress tracking and validations.
Drag and drop files to here to upload.
advanced-demo
'use client';
import { Plus } from '@primeicons/react/plus';
import { Times } from '@primeicons/react/times';
import { Upload } from '@primeicons/react/upload';
import { toast } from '@primereact/headless/toaster';
import { FileUploadRootInstance } from '@primereact/types/shared/fileupload';
import { ToasterRegionInstance, ToastType } from '@primereact/types/shared/toaster';
import { Button } from '@primereact/ui/button';
import { FileUpload } from '@primereact/ui/fileupload';
import { Message } from '@primereact/ui/message';
import { ProgressBar } from '@primereact/ui/progressbar';
import { Toast } from '@primereact/ui/toast';
import { Toaster } from '@primereact/ui/toaster';
export default function AdvancedDemo() {
const onUpload = () => {
toast({
title: 'Success',
description: 'File Uploaded',
group: 'advanced-demo'
});
};
return (
<div>
<FileUpload.Root
name="demo[]"
url="/api/upload"
multiple
accept="image/*"
maxFileSize={1000000}
className="border border-surface-200 dark:border-surface-700 rounded-md"
onUpload={onUpload}
>
{(instance: FileUploadRootInstance) => {
return (
<>
<div className="flex items-center p-5 gap-2">
<Button onClick={instance.choose}>
<Plus />
Choose
</Button>
<Button severity="secondary" disabled={!instance.hasFiles} onClick={instance.upload}>
<Upload />
Upload
</Button>
<Button severity="secondary" disabled={!instance.hasFiles} onClick={instance.clear}>
<Times />
Cancel
</Button>
</div>
<FileUpload.Content>
{((instance.state.messages && instance.state.messages.length > 0) || instance.hasFiles) && (
<div className="flex flex-col gap-4">
{instance.state.messages &&
instance.state.messages.length > 0 &&
instance.state.messages.map((msg, i) => (
<Message.Root key={i} severity="error" className="mb-2">
<Message.Content>
<Message.Text>{msg}</Message.Text>
</Message.Content>
</Message.Root>
))}
{instance.hasFiles && (
<ProgressBar.Root value={instance.state.progress}>
<ProgressBar.Track style={{ height: '0.25rem' }}>
<ProgressBar.Indicator>
<ProgressBar.Label />
</ProgressBar.Indicator>
</ProgressBar.Track>
</ProgressBar.Root>
)}
</div>
)}
<FileUpload.List />
{!instance.hasFiles && !instance.hasUploadedFiles && <div>Drag and drop files to here to upload.</div>}
</FileUpload.Content>
</>
);
}}
</FileUpload.Root>
<Toaster.Root position="top-right" group="advanced-demo">
<Toaster.Portal>
<Toaster.Region>
{({ toaster }: ToasterRegionInstance) =>
toaster?.toasts.map((toast: ToastType) => (
<Toast.Root key={toast.id} toast={toast}>
<div className="grid grid-cols-[auto_1fr] items-start gap-3">
<Toast.Icon className="[&>svg]:size-3.5 mt-1 " />
<div>
<Toast.Title />
<Toast.Description className="mt-1" />
<Toast.Action as={Button} size="small" className="mt-3" />
</div>
</div>
<Toast.Close
as={Button}
iconOnly
severity={'secondary'}
variant="text"
size="small"
className={'absolute top-2 right-2'}
>
<Times />
</Toast.Close>
</Toast.Root>
))
}
</Toaster.Region>
</Toaster.Portal>
</Toaster.Root>
</div>
);
}
Template#
Uploader UI can be customized with templating.
Drag and drop files to here to upload.
template-demo
'use client';
import { FileUploadRootInstance, FileUploadSelectEvent } from '@primereact/types/shared/fileupload';
import { Badge } from '@primereact/ui/badge';
import { Button } from '@primereact/ui/button';
import { FileUpload } from '@primereact/ui/fileupload';
import { Message } from '@primereact/ui/message';
import { ProgressBar } from '@primereact/ui/progressbar';
import * as React from 'react';
import { Times } from '@primeicons/react/times';
import { CloudUpload } from '@primeicons/react/cloud-upload';
import { Images } from '@primeicons/react/images';
export default function TemplateDemo() {
const fileUploadRef = React.useRef<FileUploadRootInstance>(null);
const [totalSize, setTotalSize] = React.useState(0);
const [totalSizePercent, setTotalSizePercent] = React.useState(0);
const onRemoveFileCallback = (cb: ((index: number) => void) | undefined, file: File, index: number) => {
if (!fileUploadRef.current || !cb) return;
const fileSizeStr = fileUploadRef.current.formatSize(file.size);
const _totalSize = totalSize - parseInt(fileSizeStr);
cb(index);
setTotalSize(_totalSize);
setTotalSizePercent(_totalSize / 10000);
};
const onSelect = (e: FileUploadSelectEvent) => {
if (!fileUploadRef.current) return;
let _totalSize = totalSize;
const files = e.files;
files.forEach((file) => {
const fileSizeStr = fileUploadRef.current!.formatSize(file.size);
_totalSize += parseInt(fileSizeStr);
});
setTotalSize(_totalSize);
setTotalSizePercent(_totalSize / 10);
};
return (
<div>
<FileUpload.Root
ref={fileUploadRef}
name="demo[]"
url="/api/upload"
multiple
accept="image/*"
maxFileSize={1000000}
className="border border-surface-200 dark:border-surface-700 rounded-md"
onSelect={onSelect}
>
{(instance: FileUploadRootInstance) => {
return (
<>
<div className="flex items-center p-5 gap-2">
<div className="flex flex-wrap justify-between items-center flex-1 gap-4">
<div className="flex gap-2">
<Button onClick={instance.choose} iconOnly rounded variant="outlined" severity="secondary">
<Images />
</Button>
<Button
onClick={instance.upload}
iconOnly
rounded
variant="outlined"
severity="success"
disabled={!instance.hasFiles}
>
<CloudUpload />
</Button>
<Button
onClick={instance.clear}
iconOnly
rounded
variant="outlined"
severity="danger"
disabled={!instance.hasFiles}
>
<Times />
</Button>
</div>
<ProgressBar.Root value={totalSizePercent}>
<ProgressBar.Track className="md:w-20rem w-full md:ml-auto">
<ProgressBar.Indicator>
<ProgressBar.Label />
</ProgressBar.Indicator>
</ProgressBar.Track>
</ProgressBar.Root>
</div>
</div>
<FileUpload.Content>
<div className="flex flex-col gap-8 pt-4">
{instance.state.messages &&
instance.state.messages.length > 0 &&
instance.state.messages.map((msg, i) => (
<Message.Root key={i} severity="error" className="mb-2">
<Message.Content>
<Message.Text>{msg}</Message.Text>
</Message.Content>
</Message.Root>
))}
{instance.hasFiles && (
<>
<h5 className="font-semibold">Pending</h5>
<div className="flex flex-wrap gap-4">
{instance.state.files.map((file, index) => (
<div
key={file.name + file.type + file.size}
className="p-8 rounded-border flex flex-col border border-surface items-center gap-4"
>
<div>
<img
role="presentation"
alt={file.name}
src={URL.createObjectURL(file)}
width="100"
height="50"
/>
</div>
<span className="font-semibold text-ellipsis max-w-60 whitespace-nowrap overflow-hidden">
{file.name}
</span>
<div>{instance?.formatSize(file.size)}</div>
<Badge severity="warn">Pending</Badge>
<Button
variant="text"
rounded
iconOnly
severity="danger"
onClick={() => onRemoveFileCallback(instance?.remove, file, index)}
>
<Times />
</Button>
</div>
))}
</div>
</>
)}
{instance.hasUploadedFiles && (
<>
<h5 className="font-semibold">Completed</h5>
<div className="flex flex-wrap gap-4">
{instance.state.uploadedFiles.map((file, index) => (
<div
key={file.name + file.type + file.size}
className="p-8 rounded-border flex flex-col border border-surface items-center gap-4"
>
<div>
<img
role="presentation"
alt={file.name}
src={URL.createObjectURL(file)}
width="100"
height="50"
/>
</div>
<span className="font-semibold text-ellipsis max-w-60 whitespace-nowrap overflow-hidden">
{file.name}
</span>
<div>{instance.formatSize(file.size)}</div>
<Badge severity="success" className="mt-4">
Completed
</Badge>
<Button
variant="text"
rounded
iconOnly
severity="danger"
onClick={() => instance?.removeUploadedFile(index)}
>
<Times />
</Button>
</div>
))}
</div>
</>
)}
{!instance.hasFiles && !instance.hasUploadedFiles && (
<>
<div className="flex items-center justify-center flex-col">
<CloudUpload className="border-2 rounded-full p-8 text-4xl text-muted-color" />
<p className="mt-6 mb-0">Drag and drop files to here to upload.</p>
</div>
</>
)}
</div>
</FileUpload.Content>
</>
);
}}
</FileUpload.Root>
</div>
);
}
Custom Upload#
Uploading implementation can be overridden by enabling customUpload property. This sample, displays the image on the client side with a grayscale filter.
custom-upload-demo
'use client';
import { FileUploadHandlerEvent, FileUploadRootInstance } from '@primereact/types/shared/fileupload';
import { Button } from '@primereact/ui/button';
import { FileUpload } from '@primereact/ui/fileupload';
import * as React from 'react';
import { Plus } from '@primeicons/react/plus';
export default function CustomUploadDemo() {
const [src, setSrc] = React.useState<string | null>(null);
const onFileSelect = (event: FileUploadHandlerEvent) => {
const file = event.files[0];
const reader = new FileReader();
reader.onload = async (e) => {
if (e.target?.result && typeof e.target.result === 'string') {
setSrc(e.target.result);
}
};
reader.readAsDataURL(file);
};
return (
<div className="flex flex-col items-center gap-6">
<FileUpload.Root url="/api/upload" auto customUpload uploadHandler={onFileSelect}>
{(instance: FileUploadRootInstance) => {
return (
<div className="flex flex-wrap items-center gap-3">
<Button onClick={instance.choose} severity="secondary" variant="outlined">
<Plus />
Browse
</Button>
</div>
);
}}
</FileUpload.Root>
{src && <img src={src} alt="Image" className="shadow-md rounded-xl w-full sm:w-64" style={{ filter: 'grayscale(100%)' }} />}
</div>
);
}