# react-dropzone
Simple HTML5 drag 'n' drop zone with React.js
# Getting Started
`react-dropzone` is a set of React hooks and components for creating a drag 'n' drop
zone for files.
## Installation
:::code-group
```bash [npm]
npm install react-dropzone
```
```bash [pnpm]
pnpm add react-dropzone
```
```bash [yarn]
yarn add react-dropzone
```
:::
`react-dropzone` ships as ESM and CommonJS with TypeScript types included, and lists
`react` as a peer dependency (`>= 18`).
:::warning[Breaking change]
`FileWithPath` (re-exported from [file-selector](https://github.com/react-dropzone/file-selector)) now types `path` and `relativePath` as **required** — a plain `File` is no longer assignable to it. The `onDrop`/`onDropAccepted` callbacks still hand you `File` objects, so type those handlers as `File[]` rather than `FileWithPath[]`.
:::
## Usage
Use the `useDropzone` hook to bind the necessary handlers to any element:
```tsx
import React from "react";
import {useDropzone} from "react-dropzone";
function MyDropzone() {
const {getRootProps, getInputProps} = useDropzone({
onDrop: acceptedFiles => {
// Do something with the files, e.g. upload to a server
console.log(acceptedFiles);
}
});
return (
Drag 'n' drop some files here, or click to select files
);
}
```
* `getRootProps()` returns the props for the root drag 'n' drop container.
* `getInputProps()` returns the props for the hidden `` used for click/keyboard access.
See the [Basic example](/examples/basic) for a live, interactive version.
# Using with Tauri (desktop apps)
Inside a [Tauri](https://tauri.app/) webview, dragging a file onto the window does **not**
fire the browser's `dragenter`/`dragover`/`drop` events by default, so a `react-dropzone`
dropzone appears to ignore drops. This is not a bug in `react-dropzone`: Tauri's native
window layer intercepts OS file drops **before** the webview sees them and emits its own
events instead. This has been the behaviour since the early betas
([tauri-apps/tauri#2768](https://github.com/tauri-apps/tauri/issues/2768)).
You have two options, depending on whether you need the real filesystem paths of dropped
files.
## Recommended: let the webview handle drops
Disable Tauri's native drag-and-drop handling. Once it's off, standard HTML5 drag-and-drop
events flow to the webview and `react-dropzone` works with **no code changes** - drag state,
`onDrop`, validation, everything. Disabling it is also required to use HTML5 drag-and-drop on
Windows.
:::code-group
```json [Tauri v2 - tauri.conf.json]
{
"app": {
"windows": [
{
"dragDropEnabled": false
}
]
}
}
```
```json [Tauri v1 - tauri.conf.json]
{
"tauri": {
"windows": [
{
"fileDropEnabled": false
}
]
}
}
```
:::
:::warning[Trade-off]
With native handling off you get sandboxed browser `File` objects, exactly as in a normal
browser - you do **not** get the absolute filesystem path of a dropped file. If you need real
paths, keep native handling on and use the approach below.
:::
## If you need absolute file paths: keep native handling on
Keep `dragDropEnabled` at its default (`true`) and listen to Tauri's own drag-and-drop event,
which hands you the absolute paths. Read each path into a `File` with the
[fs plugin](https://v2.tauri.app/plugin/file-system/), then run it through your own validation
or `react-dropzone`'s `getFilesFromEvent` helper. In this mode `react-dropzone` is only
driving the click-to-open picker and your styling - the drop itself and the drag-active state
are yours to manage, since the DOM drag events never fire.
```tsx
import {getCurrentWebviewWindow} from "@tauri-apps/api/webviewWindow";
import {readFile} from "@tauri-apps/plugin-fs";
const webview = getCurrentWebviewWindow();
const unlisten = await webview.onDragDropEvent(async event => {
// event.payload.type is "enter" | "over" | "drop" | "leave"
if (event.payload.type === "drop") {
const files = await Promise.all(
event.payload.paths.map(async path => {
const bytes = await readFile(path);
const name = path.split(/[\\/]/).pop() ?? path;
return new File([bytes], name);
})
);
// Hand `files` to your own state, or validate them with react-dropzone's
// getFilesFromEvent / the same accept/size rules you pass to useDropzone.
}
});
```
:::note
`react-dropzone`'s built-in drop pipeline can't currently be driven directly from Tauri's
events - that would need a pluggable event source in the core, tracked in
[#1316](https://github.com/react-dropzone/react-dropzone/issues/1316). For now, manage the
dropped files in your own React state and derive the drag-active UI from the `enter`/`over`/
`leave` payload types.
:::
## Version notes
Tauri renamed the config flag and the events between v1 and v2:
| | Tauri v1 | Tauri v2 |
| ----------- | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| Config flag | `tauri.windows[].fileDropEnabled` | `app.windows[].dragDropEnabled` |
| JS listener | `appWindow.onFileDropEvent()` | `getCurrentWebviewWindow().onDragDropEvent()` |
| Events | `tauri://file-drop`, `tauri://file-drop-hover`, `tauri://file-drop-cancelled` | `tauri://drag-enter`, `tauri://drag-over`, `tauri://drag-drop`, `tauri://drag-leave` |
Both default to enabled. Setting the flag to `false` is what lets `react-dropzone` handle
drops itself.
## References
* [Tauri config reference - `dragDropEnabled`](https://v2.tauri.app/reference/config/)
* [Tauri drag-and-drop discussion (v1/v2)](https://github.com/tauri-apps/tauri/discussions/9696)
* [tauri-apps/tauri#2768 - original "no support for dropping files?"](https://github.com/tauri-apps/tauri/issues/2768)
# Basic example
The `useDropzone` hook just binds the necessary handlers to create a drag 'n' drop zone.
Use the `getRootProps()` fn to get the props required for drag 'n' drop and use them on any element.
For click and keydown behavior, use the `getInputProps()` fn and use the returned props on an ``.
Furthermore, the hook supports folder drag 'n' drop by default. See [file-selector](https://github.com/react-dropzone/file-selector) for more info about supported browsers.
```tsx
import React from "react";
import {useDropzone} from "react-dropzone";
function Basic() {
const {acceptedFiles, getRootProps, getInputProps} = useDropzone();
const files = acceptedFiles.map(file => (
{file.path} - {file.size} bytes
));
return (
Drag 'n' drop some files here, or click to select files
);
}
```
## Disabled
Dropzone with the `disabled` property:
```tsx
const {getRootProps, getInputProps} = useDropzone({disabled: true});
```
# Event propagation
If you'd like to prevent drag events propagation from the child to parent, use the `noDragEventsBubbling` property on the child. Note how the outer `onDrop` is never invoked when the drop occurs on the inner dropzone:
```tsx
function InnerDropzone() {
const {getRootProps} = useDropzone({noDragEventsBubbling: true});
return (
);
}
```
## Disabling click
Turn off the default click behavior with `noClick`:
```tsx
const {getRootProps, getInputProps} = useDropzone({noClick: true});
```
## Disabling keyboard
Turn off SPACE/ENTER and focus handling with `noKeyboard`:
```tsx
const {getRootProps, getInputProps} = useDropzone({noKeyboard: true});
```
## Disabling drag
Turn off drag 'n' drop with `noDrag`:
```tsx
const {getRootProps, getInputProps} = useDropzone({noDrag: true});
```
## Stopping propagation yourself
If you provide your own handlers and call `event.stopPropagation()`, it prevents the default dropzone behavior (nothing is logged on drop here):
```tsx
console.log(files)}>
{({getRootProps, getInputProps}) => (
event.stopPropagation()})}>
)}
```
# Using Dropzone inside a form
react-dropzone does not submit files in form submissions by default. If you need this, add a hidden file input and set the files into it.
:::warning[Spreading `getRootProps()` onto a `