Skip to main content

React Dropzone

react-dropzone is a third-party library. Please refer to its official documentation for more details.

warning

It is essential to ensure that when incorporating the react-dropzone component into your project, it is correctly wrapped using the AppReactDropzone component. In scenarios where only a single instance of react-dropzone is utilized, it should be individually enclosed within the AppReactDropzone component. Conversely, if multiple instances of react-dropzone are used in one page, it becomes necessary to wrap the entire page with the AppReactDropzone component to ensure optimal styles.

Upload Multiple Files

// React Imports
import { useState } from 'react'

// MUI Imports
import List from '@mui/material/List'
import Avatar from '@mui/material/Avatar'
import Button from '@mui/material/Button'
import ListItem from '@mui/material/ListItem'
import IconButton from '@mui/material/IconButton'
import Typography from '@mui/material/Typography'

// Third-party Imports
import { useDropzone } from 'react-dropzone'

type FileProp = {
name: string
type: string
size: number
}

const FileUploaderMultiple = () => {
// States
const [files, setFiles] = useState<File[]>([])

// Hooks
const { getRootProps, getInputProps } = useDropzone({
onDrop: (acceptedFiles: File[]) => {
setFiles(acceptedFiles.map((file: File) => Object.assign(file)))
}
})

const renderFilePreview = (file: FileProp) => {
if (file.type.startsWith('image')) {
return <img width={38} height={38} alt={file.name} src={URL.createObjectURL(file as any)} />
} else {
return <i className='ri-file-text-line' />
}
}

const handleRemoveFile = (file: FileProp) => {
const uploadedFiles = files
const filtered = uploadedFiles.filter((i: FileProp) => i.name !== file.name)

setFiles([...filtered])
}

const fileList = files.map((file: FileProp) => (
<ListItem key={file.name}>
<div className='file-details'>
<div className='file-preview'>{renderFilePreview(file)}</div>
<div>
<Typography className='file-name'>{file.name}</Typography>
<Typography className='file-size' variant='body2'>
{Math.round(file.size / 100) / 10 > 1000
? `${(Math.round(file.size / 100) / 10000).toFixed(1)} mb`
: `${(Math.round(file.size / 100) / 10).toFixed(1)} kb`}
</Typography>
</div>
</div>
<IconButton onClick={() => handleRemoveFile(file)}>
<i className='ri-close-line text-xl' />
</IconButton>
</ListItem>
))

const handleRemoveAllFiles = () => {
setFiles([])
}

return (
<>
<div {...getRootProps({ className: 'dropzone' })}>
<input {...getInputProps()} />
<div className='flex items-center flex-col'>
<Avatar variant='rounded' className='bs-12 is-12 mbe-9'>
<i className='ri-upload-2-line' />
</Avatar>
<Typography variant='h4' className='mbe-2.5'>
Drop files here or click to upload.
</Typography>
<Typography color='text.secondary'>
Drop files here or click{' '}
<a href='/' onClick={e => e.preventDefault()} className='text-textPrimary no-underline'>
browse
</a>{' '}
thorough your machine
</Typography>
</div>
</div>
{files.length ? (
<>
<List>{fileList}</List>
<div className='buttons'>
<Button color='error' variant='outlined' onClick={handleRemoveAllFiles}>
Remove All
</Button>
<Button variant='contained'>Upload Files</Button>
</div>
</>
) : null}
</>
)
}

export default FileUploaderMultiple
Upload Single Files

// React Imports
import { useState } from 'react'

// MUI Imports
import Box from '@mui/material/Box'
import Avatar from '@mui/material/Avatar'
import Typography from '@mui/material/Typography'

// Third-party Imports
import { useDropzone } from 'react-dropzone'

type FileProp = {
name: string
type: string
size: number
}

const FileUploaderSingle = () => {
// States
const [files, setFiles] = useState<File[]>([])

// Hooks
const { getRootProps, getInputProps } = useDropzone({
multiple: false,
accept: {
'image/*': ['.png', '.jpg', '.jpeg', '.gif']
},
onDrop: (acceptedFiles: File[]) => {
setFiles(acceptedFiles.map((file: File) => Object.assign(file)))
}
})

const img = files.map((file: FileProp) => (
<img key={file.name} alt={file.name} className='single-file-image' src={URL.createObjectURL(file as any)} />
))

return (
<Box {...getRootProps({ className: 'dropzone' })} {...(files.length && { sx: { height: 450 } })}>
<input {...getInputProps()} />
{files.length ? (
img
) : (
<div className='flex items-center flex-col'>
<Avatar variant='rounded' className='bs-12 is-12 mbe-9'>
<i className='ri-upload-2-line' />
</Avatar>
<Typography variant='h4' className='mbe-2.5'>
Drop files here or click to upload.
</Typography>
<Typography color='text.secondary'>
Drop files here or click{' '}
<a href='/' onClick={e => e.preventDefault()} className='text-textPrimary no-underline'>
browse
</a>{' '}
thorough your machine
</Typography>
</div>
)}
</Box>
)
}

export default FileUploaderSingle
Upload Files with Restrictions

// React Imports
import { useState } from 'react'

// MUI Imports
import List from '@mui/material/List'
import Avatar from '@mui/material/Avatar'
import Button from '@mui/material/Button'
import ListItem from '@mui/material/ListItem'
import IconButton from '@mui/material/IconButton'
import Typography from '@mui/material/Typography'

// Third-party Imports
import { toast } from 'react-toastify'

// Icon Imports
import { useDropzone } from 'react-dropzone'

type FileProp = {
name: string
type: string
size: number
}

const FileUploaderRestrictions = () => {
// States
const [files, setFiles] = useState<File[]>([])

// Hooks
const { getRootProps, getInputProps } = useDropzone({
maxFiles: 2,
maxSize: 2000000,
accept: {
'image/*': ['.png', '.jpg', '.jpeg', '.gif']
},
onDrop: (acceptedFiles: File[]) => {
setFiles(acceptedFiles.map((file: File) => Object.assign(file)))
},
onDropRejected: () => {
toast.error('You can only upload 2 files & maximum size of 2 MB.', {
autoClose: 3000
})
}
})

const renderFilePreview = (file: FileProp) => {
if (file.type.startsWith('image')) {
return <img width={38} height={38} alt={file.name} src={URL.createObjectURL(file as any)} />
} else {
return <i className='ri-file-text-line' />
}
}

const handleRemoveFile = (file: FileProp) => {
const uploadedFiles = files
const filtered = uploadedFiles.filter((i: FileProp) => i.name !== file.name)

setFiles([...filtered])
}

const fileList = files.map((file: FileProp) => (
<ListItem key={file.name}>
<div className='file-details'>
<div className='file-preview'>{renderFilePreview(file)}</div>
<div>
<Typography className='file-name'>{file.name}</Typography>
<Typography className='file-size' variant='body2'>
{Math.round(file.size / 100) / 10 > 1000
? `${(Math.round(file.size / 100) / 10000).toFixed(1)} mb`
: `${(Math.round(file.size / 100) / 10).toFixed(1)} kb`}
</Typography>
</div>
</div>
<IconButton onClick={() => handleRemoveFile(file)}>
<i className='ri-close-line text-xl' />
</IconButton>
</ListItem>
))

const handleRemoveAllFiles = () => {
setFiles([])
}

return (
<>
<div {...getRootProps({ className: 'dropzone' })}>
<input {...getInputProps()} />
<div className='flex items-center flex-col'>
<Avatar variant='rounded' className='bs-12 is-12 mbe-9'>
<i className='ri-upload-2-line' />
</Avatar>
<Typography variant='h4' className='mbe-2.5'>
Drop files here or click to upload.
</Typography>
<Typography color='text.secondary'>Allowed *.jpeg, *.jpg, *.png, *.gif</Typography>
<Typography color='text.secondary'>Max 2 files and max size of 2 MB</Typography>
</div>
</div>
{files.length ? (
<>
<List>{fileList}</List>
<div className='buttons'>
<Button color='error' variant='outlined' onClick={handleRemoveAllFiles}>
Remove All
</Button>
<Button variant='contained'>Upload Files</Button>
</div>
</>
) : null}
</>
)
}

export default FileUploaderRestrictions