Simple HTML5 drag-drop zone with React.js.
Installations
npm install react-dropzone
Developer
Developer Guide
Module System
CommonJS, ESM
Min. Node Version
>= 10.13
Typescript Support
No
Node Version
20.18.0
NPM Version
10.9.0
Statistics
10,590 Stars
630 Commits
786 Forks
61 Watching
13 Branches
176 Contributors
Updated on 27 Nov 2024
Bundle Size
59.57 kB
Minified
16.51 kB
Minified + Gzipped
Languages
JavaScript (95.2%)
TypeScript (4.7%)
Shell (0.11%)
Total Downloads
Cumulative downloads
Total Downloads
565,133,396
Last day
-2.7%
686,192
Compared to previous day
Last week
3.7%
3,539,651
Compared to previous week
Last month
11.3%
14,990,709
Compared to previous month
Last year
15%
161,610,348
Compared to previous year
Daily Downloads
Weekly Downloads
Monthly Downloads
Yearly Downloads
Dependencies
3
Peer Dependencies
1
Dev Dependencies
66
react-dropzone
Simple React hook to create a HTML5-compliant drag'n'drop zone for files.
Documentation and examples at https://react-dropzone.js.org. Source code at https://github.com/react-dropzone/react-dropzone/.
Installation
Install it from npm and include it in your React build process (using Webpack, Browserify, etc).
1npm install --save react-dropzone
or:
1yarn add react-dropzone
Usage
You can either use the hook:
1import React, {useCallback} from 'react' 2import {useDropzone} from 'react-dropzone' 3 4function MyDropzone() { 5 const onDrop = useCallback(acceptedFiles => { 6 // Do something with the files 7 }, []) 8 const {getRootProps, getInputProps, isDragActive} = useDropzone({onDrop}) 9 10 return ( 11 <div {...getRootProps()}> 12 <input {...getInputProps()} /> 13 { 14 isDragActive ? 15 <p>Drop the files here ...</p> : 16 <p>Drag 'n' drop some files here, or click to select files</p> 17 } 18 </div> 19 ) 20}
Or the wrapper component for the hook:
1import React from 'react' 2import Dropzone from 'react-dropzone' 3 4<Dropzone onDrop={acceptedFiles => console.log(acceptedFiles)}> 5 {({getRootProps, getInputProps}) => ( 6 <section> 7 <div {...getRootProps()}> 8 <input {...getInputProps()} /> 9 <p>Drag 'n' drop some files here, or click to select files</p> 10 </div> 11 </section> 12 )} 13</Dropzone>
If you want to access file contents you have to use the FileReader API:
1import React, {useCallback} from 'react' 2import {useDropzone} from 'react-dropzone' 3 4function MyDropzone() { 5 const onDrop = useCallback((acceptedFiles) => { 6 acceptedFiles.forEach((file) => { 7 const reader = new FileReader() 8 9 reader.onabort = () => console.log('file reading was aborted') 10 reader.onerror = () => console.log('file reading has failed') 11 reader.onload = () => { 12 // Do whatever you want with the file contents 13 const binaryStr = reader.result 14 console.log(binaryStr) 15 } 16 reader.readAsArrayBuffer(file) 17 }) 18 19 }, []) 20 const {getRootProps, getInputProps} = useDropzone({onDrop}) 21 22 return ( 23 <div {...getRootProps()}> 24 <input {...getInputProps()} /> 25 <p>Drag 'n' drop some files here, or click to select files</p> 26 </div> 27 ) 28}
Dropzone Props Getters
The dropzone property getters are just two functions that return objects with properties which you need to use to create the drag 'n' drop zone.
The root properties can be applied to whatever element you want, whereas the input properties must be applied to an <input>
:
1import React from 'react' 2import {useDropzone} from 'react-dropzone' 3 4function MyDropzone() { 5 const {getRootProps, getInputProps} = useDropzone() 6 7 return ( 8 <div {...getRootProps()}> 9 <input {...getInputProps()} /> 10 <p>Drag 'n' drop some files here, or click to select files</p> 11 </div> 12 ) 13}
Note that whatever other props you want to add to the element where the props from getRootProps()
are set, you should always pass them through that function rather than applying them on the element itself.
This is in order to avoid your props being overridden (or overriding the props returned by getRootProps()
):
1<div 2 {...getRootProps({ 3 onClick: event => console.log(event), 4 role: 'button', 5 'aria-label': 'drag and drop area', 6 ... 7 })} 8/>
In the example above, the provided {onClick}
handler will be invoked before the internal one, therefore, internal callbacks can be prevented by simply using stopPropagation.
See Events for more examples.
Important: if you omit rendering an <input>
and/or binding the props from getInputProps()
, opening a file dialog will not be possible.
Refs
Both getRootProps
and getInputProps
accept a custom refKey
(defaults to ref
) as one of the attributes passed down in the parameter.
This can be useful when the element you're trying to apply the props from either one of those fns does not expose a reference to the element, e.g:
1import React from 'react' 2import {useDropzone} from 'react-dropzone' 3// NOTE: After v4.0.0, styled components exposes a ref using forwardRef, 4// therefore, no need for using innerRef as refKey 5import styled from 'styled-components' 6 7const StyledDiv = styled.div` 8 // Some styling here 9` 10function Example() { 11 const {getRootProps, getInputProps} = useDropzone() 12 <StyledDiv {...getRootProps({ refKey: 'innerRef' })}> 13 <input {...getInputProps()} /> 14 <p>Drag 'n' drop some files here, or click to select files</p> 15 </StyledDiv> 16}
If you're working with Material UI v4 and would like to apply the root props on some component that does not expose a ref, use RootRef:
1import React from 'react' 2import {useDropzone} from 'react-dropzone' 3import RootRef from '@material-ui/core/RootRef' 4 5function PaperDropzone() { 6 const {getRootProps, getInputProps} = useDropzone() 7 const {ref, ...rootProps} = getRootProps() 8 9 <RootRef rootRef={ref}> 10 <Paper {...rootProps}> 11 <input {...getInputProps()} /> 12 <p>Drag 'n' drop some files here, or click to select files</p> 13 </Paper> 14 </RootRef> 15}
IMPORTANT: do not set the ref
prop on the elements where getRootProps()
/getInputProps()
props are set, instead, get the refs from the hook itself:
1import React from 'react' 2import {useDropzone} from 'react-dropzone' 3 4function Refs() { 5 const { 6 getRootProps, 7 getInputProps, 8 rootRef, // Ref to the `<div>` 9 inputRef // Ref to the `<input>` 10 } = useDropzone() 11 <div {...getRootProps()}> 12 <input {...getInputProps()} /> 13 <p>Drag 'n' drop some files here, or click to select files</p> 14 </div> 15}
If you're using the <Dropzone>
component, though, you can set the ref
prop on the component itself which will expose the {open}
prop that can be used to open the file dialog programmatically:
1import React, {createRef} from 'react' 2import Dropzone from 'react-dropzone' 3 4const dropzoneRef = createRef() 5 6<Dropzone ref={dropzoneRef}> 7 {({getRootProps, getInputProps}) => ( 8 <div {...getRootProps()}> 9 <input {...getInputProps()} /> 10 <p>Drag 'n' drop some files here, or click to select files</p> 11 </div> 12 )} 13</Dropzone> 14 15dropzoneRef.open()
Testing
react-dropzone
makes some of its drag 'n' drop callbacks asynchronous to enable promise based getFilesFromEvent()
functions. In order to test components that use this library, you need to use the react-testing-library:
1import React from 'react' 2import Dropzone from 'react-dropzone' 3import {act, fireEvent, render} from '@testing-library/react' 4 5test('invoke onDragEnter when dragenter event occurs', async () => { 6 const file = new File([ 7 JSON.stringify({ping: true}) 8 ], 'ping.json', { type: 'application/json' }) 9 const data = mockData([file]) 10 const onDragEnter = jest.fn() 11 12 const ui = ( 13 <Dropzone onDragEnter={onDragEnter}> 14 {({ getRootProps, getInputProps }) => ( 15 <div {...getRootProps()}> 16 <input {...getInputProps()} /> 17 </div> 18 )} 19 </Dropzone> 20 ) 21 const { container } = render(ui) 22 23 await act( 24 () => fireEvent.dragEnter( 25 container.querySelector('div'), 26 data, 27 ) 28 ); 29 expect(onDragEnter).toHaveBeenCalled() 30}) 31 32function mockData(files) { 33 return { 34 dataTransfer: { 35 files, 36 items: files.map(file => ({ 37 kind: 'file', 38 type: file.type, 39 getAsFile: () => file 40 })), 41 types: ['Files'] 42 } 43 } 44}
NOTE: using Enzyme for testing is not supported at the moment, see #2011.
More examples for this can be found in react-dropzone
's own test suites.
Caveats
Required React Version
React 16.8 or above is required because we use hooks (the lib itself is a hook).
File Paths
Files returned by the hook or passed as arg to the onDrop
cb won't have the properties path
or fullPath
.
For more inf check this SO question and this issue.
Not a File Uploader
This lib is not a file uploader; as such, it does not process files or provide any way to make HTTP requests to some server; if you're looking for that, checkout filepond or uppy.io.
Using <label> as Root
If you use <label> as the root element, the file dialog will be opened twice; see #1107 why. To avoid this, use noClick
:
1import React, {useCallback} from 'react' 2import {useDropzone} from 'react-dropzone' 3 4function MyDropzone() { 5 const {getRootProps, getInputProps} = useDropzone({noClick: true}) 6 7 return ( 8 <label {...getRootProps()}> 9 <input {...getInputProps()} /> 10 </label> 11 ) 12}
Using open() on Click
If you bind a click event on an inner element and use open()
, it will trigger a click on the root element too, resulting in the file dialog opening twice. To prevent this, use the noClick
on the root:
1import React, {useCallback} from 'react' 2import {useDropzone} from 'react-dropzone' 3 4function MyDropzone() { 5 const {getRootProps, getInputProps, open} = useDropzone({noClick: true}) 6 7 return ( 8 <div {...getRootProps()}> 9 <input {...getInputProps()} /> 10 <button type="button" onClick={open}> 11 Open 12 </button> 13 </div> 14 ) 15}
File Dialog Cancel Callback
The onFileDialogCancel()
cb is unstable in most browsers, meaning, there's a good chance of it being triggered even though you have selected files.
We rely on using a timeout of 300ms
after the window is focused (the window onfocus
event is triggered when the file select dialog is closed) to check if any files were selected and trigger onFileDialogCancel
if none were selected.
As one can imagine, this doesn't really work if there's a lot of files or large files as by the time we trigger the check, the browser is still processing the files and no onchange
events are triggered yet on the input. Check #1031 for more info.
Fortunately, there's the File System Access API, which is currently a working draft and some browsers support it (see browser compatibility), that provides a reliable way to prompt the user for file selection and capture cancellation.
Also keep in mind that the FS access API can only be used in secure contexts.
NOTE You can enable using the FS access API with the useFsAccessApi
property: useDropzone({useFsAccessApi: true})
.
File System Access API
When setting useFsAccessApi
to true
, you're switching to the File System API (see the file system access RFC).
What this essentially does is that it will use the showOpenFilePicker method to open the file picker window so that the user can select files.
In contrast, the traditional way (when the useFsAccessApi
is not set to true
or not specified) uses an <input type="file">
(see docs) on which a click event is triggered.
With the use of the file system access API enabled, there's a couple of caveats to keep in mind:
- The users will not be able to select directories
- It requires the app to run in a secure context
- In Electron, the path may not be set (see #1249)
Supported Browsers
We use browserslist config to state the browser support for this lib, so check it out on browserslist.dev.
Need image editing?
React Dropzone integrates perfectly with Pintura Image Editor, creating a modern image editing experience. Pintura supports crop aspect ratios, resizing, rotating, cropping, annotating, filtering, and much more.
Checkout the Pintura integration example.
Support
Backers
Support us with a monthly donation and help us continue our activities. [Become a backer]
Sponsors
Become a sponsor and get your logo on our README on Github with a link to your site. [Become a sponsor]
Hosting
react-dropzone.js.org hosting provided by netlify.
Contribute
Checkout the organization CONTRIBUTING.md.
License
MIT
No vulnerabilities found.
Reason
29 commit(s) and 30 issue activity found in the last 90 days -- score normalized to 10
Reason
no dangerous workflow patterns detected
Reason
no binaries found in the repo
Reason
license file detected
Details
- Info: project has a license file: LICENSE:0
- Info: FSF or OSI recognized license: MIT License: LICENSE:0
Reason
packaging workflow detected
Details
- Info: Project packages its releases by way of GitHub Actions.: .github/workflows/release.yml:8
Reason
Found 8/21 approved changesets -- score normalized to 3
Reason
detected GitHub workflow tokens with excessive permissions
Details
- Warn: no topLevel permission defined: .github/workflows/release.yml:1
- Warn: no topLevel permission defined: .github/workflows/test.yml:1
- Info: no jobLevel write permissions found
Reason
dependency not pinned by hash detected -- score normalized to 0
Details
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yml:12: update your workflow using https://app.stepsecurity.io/secureworkflow/react-dropzone/react-dropzone/release.yml/master?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yml:13: update your workflow using https://app.stepsecurity.io/secureworkflow/react-dropzone/react-dropzone/release.yml/master?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:17: update your workflow using https://app.stepsecurity.io/secureworkflow/react-dropzone/react-dropzone/test.yml/master?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/react-dropzone/react-dropzone/test.yml/master?enable=pin
- Warn: third-party GitHubAction not pinned by hash: .github/workflows/test.yml:26: update your workflow using https://app.stepsecurity.io/secureworkflow/react-dropzone/react-dropzone/test.yml/master?enable=pin
- Warn: third-party GitHubAction not pinned by hash: .github/workflows/test.yml:34: update your workflow using https://app.stepsecurity.io/secureworkflow/react-dropzone/react-dropzone/test.yml/master?enable=pin
- Info: 0 out of 4 GitHub-owned GitHubAction dependencies pinned
- Info: 0 out of 2 third-party GitHubAction dependencies pinned
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
project is not fuzzed
Details
- Warn: no fuzzer integrations found
Reason
security policy file not detected
Details
- Warn: no security policy file detected
- Warn: no security file to analyze
- Warn: no security file to analyze
- Warn: no security file to analyze
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
- Warn: 0 commits out of 30 are checked with a SAST tool
Reason
67 existing vulnerabilities detected
Details
- Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92
- Warn: Project is vulnerable to: GHSA-93q8-gq69-wqmw
- Warn: Project is vulnerable to: GHSA-fwr7-v2mv-hh25
- Warn: Project is vulnerable to: GHSA-qwcr-r2fm-qrc7
- Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg
- Warn: Project is vulnerable to: GHSA-x9w5-v3q2-3rhw
- Warn: Project is vulnerable to: GHSA-pxg6-pf52-xh8x
- Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275
- Warn: Project is vulnerable to: GHSA-w573-4hg7-7wgq
- Warn: Project is vulnerable to: GHSA-434g-2637-qmqr
- Warn: Project is vulnerable to: GHSA-49q7-c7j4-3p7m
- Warn: Project is vulnerable to: GHSA-977x-g7h5-7qgw
- Warn: Project is vulnerable to: GHSA-f7q4-pwc6-w24p
- Warn: Project is vulnerable to: GHSA-fc9h-whq2-v747
- Warn: Project is vulnerable to: GHSA-4gmj-3p3h-gm8h
- Warn: Project is vulnerable to: GHSA-6h5x-7c5m-7cr7
- Warn: Project is vulnerable to: GHSA-rv95-896h-c2vc
- Warn: Project is vulnerable to: GHSA-qw6h-vgh9-j6wx
- Warn: Project is vulnerable to: GHSA-pw2r-vq6v-hr8c
- Warn: Project is vulnerable to: GHSA-jchw-25xp-jwwc
- Warn: Project is vulnerable to: GHSA-cxjh-pqwp-8mfp
- Warn: Project is vulnerable to: GHSA-pfrx-2q88-qq97
- Warn: Project is vulnerable to: GHSA-rc47-6667-2j5j
- Warn: Project is vulnerable to: GHSA-c7qv-q95q-8v27
- Warn: Project is vulnerable to: GHSA-78xj-cgh5-2h22
- Warn: Project is vulnerable to: GHSA-2p57-rm9w-gvfp
- Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h
- Warn: Project is vulnerable to: GHSA-76p3-8jx3-jpfq
- Warn: Project is vulnerable to: GHSA-3rfm-jhwj-7488
- Warn: Project is vulnerable to: GHSA-hhq3-ff78-jv3g
- Warn: Project is vulnerable to: GHSA-6vfc-qv3f-vr6c
- Warn: Project is vulnerable to: GHSA-4wx3-54gh-9fr9
- Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv
- Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3
- Warn: Project is vulnerable to: GHSA-xvch-5gv4-984h
- Warn: Project is vulnerable to: GHSA-5rrq-pxf6-6jx5
- Warn: Project is vulnerable to: GHSA-8fr3-hfg3-gpgp
- Warn: Project is vulnerable to: GHSA-gf8q-jrpm-jvxq
- Warn: Project is vulnerable to: GHSA-2r2c-g63r-vccr
- Warn: Project is vulnerable to: GHSA-cfm4-qjh2-4765
- Warn: Project is vulnerable to: GHSA-x4jg-mjrx-434g
- Warn: Project is vulnerable to: GHSA-9wv6-86v2-598j
- Warn: Project is vulnerable to: GHSA-7fh5-64p2-3v2j
- Warn: Project is vulnerable to: GHSA-3949-f494-cm99
- Warn: Project is vulnerable to: GHSA-hrpp-h998-j3pp
- Warn: Project is vulnerable to: GHSA-gcx4-mw62-g8wm
- Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw
- Warn: Project is vulnerable to: GHSA-44c6-4v22-4mhx
- Warn: Project is vulnerable to: GHSA-4x5v-gmq8-25ch
- Warn: Project is vulnerable to: GHSA-m6fv-jmcg-4jfg
- Warn: Project is vulnerable to: GHSA-h9rv-jmmf-4pgx
- Warn: Project is vulnerable to: GHSA-hxcc-f52p-wc94
- Warn: Project is vulnerable to: GHSA-cm22-4g7w-348p
- Warn: Project is vulnerable to: GHSA-vx3p-948g-6vhq
- Warn: Project is vulnerable to: GHSA-f5x3-32g6-xq36
- Warn: Project is vulnerable to: GHSA-4wf5-vphf-c2xc
- Warn: Project is vulnerable to: GHSA-72xf-g2v4-qvf3
- Warn: Project is vulnerable to: GHSA-7p7h-4mm5-852v
- Warn: Project is vulnerable to: GHSA-rqff-837h-mm52
- Warn: Project is vulnerable to: GHSA-8v38-pw62-9cw2
- Warn: Project is vulnerable to: GHSA-hgjh-723h-mx2j
- Warn: Project is vulnerable to: GHSA-jf5r-8hm2-f872
- Warn: Project is vulnerable to: GHSA-hc6q-2mpp-qw7j
- Warn: Project is vulnerable to: GHSA-4vvj-4cpr-p986
- Warn: Project is vulnerable to: GHSA-wr3j-pwj9-hqq6
- Warn: Project is vulnerable to: GHSA-j8xg-fqg3-53r7
- Warn: Project is vulnerable to: GHSA-3h5v-q93c-6h6q
Score
4.5
/10
Last Scanned on 2024-11-18
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn MoreOther packages similar to react-dropzone
vue3-dropzone
It's inspired by [react-dropzone](https://github.com/react-dropzone/react-dropzone) and implemented with vue3.
react-dropzone-s3-uploader
Drag and drop s3 file uploader via react-dropzone + react-s3-uploader
shadcn-dropzone
Ready to use File Upload Dropzone component, built with shadcn/ui and react-dropzone.
organism-react-dropzone
React dropzone