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
- TSX
- JS
// 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
// 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'
const FileUploaderMultiple = () => {
// States
const [files, setFiles] = useState([])
// Hooks
const { getRootProps, getInputProps } = useDropzone({
onDrop: acceptedFiles => {
setFiles(acceptedFiles.map(file => Object.assign(file)))
}
})
const renderFilePreview = file => {
if (file.type.startsWith('image')) {
return <img width={38} height={38} alt={file.name} src={URL.createObjectURL(file)} />
} else {
return <i className='ri-file-text-line' />
}
}
const handleRemoveFile = file => {
const uploadedFiles = files
const filtered = uploadedFiles.filter(i => i.name !== file.name)
setFiles([...filtered])
}
const fileList = files.map(file => (
<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
- TSX
- JS
// 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
// 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'
const FileUploaderSingle = () => {
// States
const [files, setFiles] = useState([])
// Hooks
const { getRootProps, getInputProps } = useDropzone({
multiple: false,
accept: {
'image/*': ['.png', '.jpg', '.jpeg', '.gif']
},
onDrop: acceptedFiles => {
setFiles(acceptedFiles.map(file => Object.assign(file)))
}
})
const img = files.map(file => (
<img key={file.name} alt={file.name} className='single-file-image' src={URL.createObjectURL(file)} />
))
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
Drop files here or click to upload.
Allowed *.jpeg, *.jpg, *.png, *.gif
Max 2 files and max size of 2 MB
- TSX
- JS
// 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
// 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'
const FileUploaderRestrictions = () => {
// States
const [files, setFiles] = useState([])
// Hooks
const { getRootProps, getInputProps } = useDropzone({
maxFiles: 2,
maxSize: 2000000,
accept: {
'image/*': ['.png', '.jpg', '.jpeg', '.gif']
},
onDrop: acceptedFiles => {
setFiles(acceptedFiles.map(file => Object.assign(file)))
},
onDropRejected: () => {
toast.error('You can only upload 2 files & maximum size of 2 MB.', {
autoClose: 3000
})
}
})
const renderFilePreview = file => {
if (file.type.startsWith('image')) {
return <img width={38} height={38} alt={file.name} src={URL.createObjectURL(file)} />
} else {
return <i className='ri-file-text-line' />
}
}
const handleRemoveFile = file => {
const uploadedFiles = files
const filtered = uploadedFiles.filter(i => i.name !== file.name)
setFiles([...filtered])
}
const fileList = files.map(file => (
<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