![react-dropzone logo](https://raw.githubusercontent.com/react-dropzone/react-dropzone/master/logo/logo.png) # react-dropzone [![npm](https://img.shields.io/npm/v/react-dropzone.svg?style=flat-square)](https://www.npmjs.com/package/react-dropzone) [![Tests](https://img.shields.io/github/workflow/status/react-dropzone/react-dropzone/Test?label=tests&style=flat-square)](https://github.com/react-dropzone/react-dropzone/actions?query=workflow%3ATest) [![codecov](https://img.shields.io/codecov/c/gh/react-dropzone/react-dropzone/master.svg?style=flat-square)](https://codecov.io/gh/react-dropzone/react-dropzone) [![Open Collective Backers](https://img.shields.io/opencollective/backers/react-dropzone.svg?style=flat-square)](#backers) [![Open Collective Sponsors](https://img.shields.io/opencollective/sponsors/react-dropzone.svg?style=flat-square)](#sponsors) [![Gitpod](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod&style=flat-square)](https://gitpod.io/#https://github.com/react-dropzone/react-dropzone) [![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg?style=flat-square)](https://github.com/react-dropzone/.github/blob/main/CODE_OF_CONDUCT.md) 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](http://webpack.github.io/), [Browserify](http://browserify.org/), etc). ```bash npm install --save react-dropzone ``` or: ```bash yarn add react-dropzone ``` ## Usage You can either use the hook: ```jsx static import React, {useCallback} from 'react' import {useDropzone} from 'react-dropzone' function MyDropzone() { const onDrop = useCallback(acceptedFiles => { // Do something with the files }, []) const {getRootProps, getInputProps, isDragActive} = useDropzone({onDrop}) return (
{ isDragActive ?

Drop the files here ...

:

Drag 'n' drop some files here, or click to select files

}
) } ``` Or the wrapper component for the hook: ```jsx static import React from 'react' import Dropzone from 'react-dropzone' console.log(acceptedFiles)}> {({getRootProps, getInputProps}) => (

Drag 'n' drop some files here, or click to select files

)}
``` If you want to access file contents you have to use the [FileReader API](https://developer.mozilla.org/en-US/docs/Web/API/FileReader): ```jsx static import React, {useCallback} from 'react' import {useDropzone} from 'react-dropzone' function MyDropzone() { const onDrop = useCallback((acceptedFiles) => { acceptedFiles.forEach((file) => { const reader = new FileReader() reader.onabort = () => console.log('file reading was aborted') reader.onerror = () => console.log('file reading has failed') reader.onload = () => { // Do whatever you want with the file contents const binaryStr = reader.result console.log(binaryStr) } reader.readAsArrayBuffer(file) }) }, []) const {getRootProps, getInputProps} = useDropzone({onDrop}) return (

Drag 'n' drop some files here, or click to select files

) } ``` ## 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 ``: ```jsx static import React from 'react' import {useDropzone} from 'react-dropzone' function MyDropzone() { const {getRootProps, getInputProps} = useDropzone() return (

Drag 'n' drop some files here, or click to select files

) } ``` 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()`): ```jsx static
console.log(event), role: 'button', 'aria-label': 'drag and drop area', ... })} /> ``` 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](https://developer.mozilla.org/en-US/docs/Web/API/Event/stopPropagation). See [Events](https://react-dropzone.js.org#events) for more examples. *Important*: if you omit rendering an `` 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: ```jsx static import React from 'react' import {useDropzone} from 'react-dropzone' // NOTE: After v4.0.0, styled components exposes a ref using forwardRef, // therefore, no need for using innerRef as refKey import styled from 'styled-components' const StyledDiv = styled.div` // Some styling here ` function Example() { const {getRootProps, getInputProps} = useDropzone()

Drag 'n' drop some files here, or click to select files

} ``` If you're working with [Material UI v4](https://v4.mui.com/) and would like to apply the root props on some component that does not expose a ref, use [RootRef](https://v4.mui.com/api/root-ref/): ```jsx static import React from 'react' import {useDropzone} from 'react-dropzone' import RootRef from '@material-ui/core/RootRef' function PaperDropzone() { const {getRootProps, getInputProps} = useDropzone() const {ref, ...rootProps} = getRootProps()

Drag 'n' drop some files here, or click to select files

} ``` **IMPORTANT**: do not set the `ref` prop on the elements where `getRootProps()`/`getInputProps()` props are set, instead, get the refs from the hook itself: ```jsx static import React from 'react' import {useDropzone} from 'react-dropzone' function Refs() { const { getRootProps, getInputProps, rootRef, // Ref to the `
` inputRef // Ref to the `` } = useDropzone()

Drag 'n' drop some files here, or click to select files

} ``` If you're using the `` 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: ```jsx static import React, {createRef} from 'react' import Dropzone from 'react-dropzone' const dropzoneRef = createRef() {({getRootProps, getInputProps}) => (

Drag 'n' drop some files here, or click to select files

)}
dropzoneRef.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](https://github.com/testing-library/react-testing-library): ```js static import React from 'react' import Dropzone from 'react-dropzone' import {act, fireEvent, render} from '@testing-library/react' test('invoke onDragEnter when dragenter event occurs', async () => { const file = new File([ JSON.stringify({ping: true}) ], 'ping.json', { type: 'application/json' }) const data = mockData([file]) const onDragEnter = jest.fn() const ui = ( {({ getRootProps, getInputProps }) => (
)}
) const { container } = render(ui) await act( () => fireEvent.dragEnter( container.querySelector('div'), data, ) ); expect(onDragEnter).toHaveBeenCalled() }) function mockData(files) { return { dataTransfer: { files, items: files.map(file => ({ kind: 'file', type: file.type, getAsFile: () => file })), types: ['Files'] } } } ``` **NOTE**: using [Enzyme](https://airbnb.io/enzyme) for testing is not supported at the moment, see [#2011](https://github.com/airbnb/enzyme/issues/2011). More examples for this can be found in `react-dropzone`'s own [test suites](https://github.com/react-dropzone/react-dropzone/blob/master/src/index.spec.js). ## Caveats ### Required React Version React [16.8](https://reactjs.org/blog/2019/02/06/react-v16.8.0.html) or above is required because we use [hooks](https://reactjs.org/docs/hooks-intro.html) (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](https://stackoverflow.com/a/23005925/2275818) and [this issue](https://github.com/react-dropzone/react-dropzone/issues/477). ### 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](https://pqina.nl/filepond) or [uppy.io](https://uppy.io/). ### Using \ as Root If you use [\](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/label) as the root element, the file dialog will be opened twice; see [#1107](https://github.com/react-dropzone/react-dropzone/issues/1107) why. To avoid this, use `noClick`: ```jsx static import React, {useCallback} from 'react' import {useDropzone} from 'react-dropzone' function MyDropzone() { const {getRootProps, getInputProps} = useDropzone({noClick: true}) return ( ) } ``` ### 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: ```jsx static import React, {useCallback} from 'react' import {useDropzone} from 'react-dropzone' function MyDropzone() { const {getRootProps, getInputProps, open} = useDropzone({noClick: true}) return (
) } ``` ### 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](https://github.com/react-dropzone/react-dropzone/issues/1031) for more info. Fortunately, there's the [File System Access API](https://developer.mozilla.org/en-US/docs/Web/API/File_System_Access_API), which is currently a working draft and some browsers support it (see [browser compatibility](https://developer.mozilla.org/en-US/docs/Web/API/window/showOpenFilePicker#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](https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts). **NOTE** You can disable using the FS access API with the `useFsAccessApi` property: `useDropzone({useFsAccessApi: false})`. ## Supported Browsers We use [browserslist](https://github.com/browserslist/browserslist) config to state the browser support for this lib, so check it out on [browserslist.dev](https://browserslist.dev/?q=ZGVmYXVsdHM%3D). ## Need image editing? React Dropzone integrates perfectly with [Pintura Image Editor](https://pqina.nl/pintura/?ref=react-dropzone), creating a modern image editing experience. Pintura supports crop aspect ratios, resizing, rotating, cropping, annotating, filtering, and much more. Checkout the [Pintura integration example](https://codesandbox.io/s/react-dropzone-pintura-40xh4?file=/src/App.js). ## Support ### Backers Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/react-dropzone#backer)] ### Sponsors Become a sponsor and get your logo on our README on Github with a link to your site. [[Become a sponsor](https://opencollective.com/react-dropzone#sponsor)] ### Hosting [react-dropzone.js.org](https://react-dropzone.js.org/) hosting provided by [netlify](https://www.netlify.com/). ## License MIT