> ## Documentation Index
> Fetch the complete documentation index at: https://mediadrop.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Build a working dropzone in a few lines

## Prerequisites

* [Install react-mediadrop](/getting-started/installation)

## 1. Build a dropzone

```tsx theme={"theme":{"light":"github-light","dark":"vesper"}}
"use client";

import { useMediaDrop } from "react-mediadrop";

export function UploadBox() {
	const {
		getRootProps,
		getInputProps,
		files,
		isDragActive,
		isDragReject,
		open,
		removeFile,
	} = useMediaDrop({
		restrictions: {
			accept: ["image/png", "image/jpeg", "image/webp"],
			maxFiles: 5,
			maxSize: 5 * 1024 * 1024,
		},
	});

	return (
		<div {...getRootProps()}>
			<input {...getInputProps()} />
			<p>{isDragActive ? "Drop it!" : "Drag files here"}</p>

			{files.map((item) => (
				<div key={item.id}>
					{item.name}
					{item.status === "rejected" ? (
						<span>
							{" "}
							— {item.errors.map((error) => error.message).join(", ")}
						</span>
					) : null}
					<button type="button" onClick={() => removeFile(item.id)}>
						Remove
					</button>
				</div>
			))}

			<button type="button" onClick={open}>
				Choose files
			</button>

			{isDragReject ? <p>Some files are not allowed</p> : null}
		</div>
	);
}
```

Drop or pick a file. It appears in the list below the dropzone, with a
Remove button; drop a file over 5MB or the wrong type and its rejection
reason appears next to it instead.

`getRootProps()` already makes the root click- and keyboard-activatable
(Space/Enter opens the file picker) — no separate "Choose files" button is
required unless you want one. Pass `noClick`/`noKeyboard`/`noDrag` to
`useMediaDrop()` to opt out of any of that. See [Core concepts](/guides/core-concepts)
for the full file model.

## 2. Add upload

Pass a `transport` and the hook additionally returns `uploadFile`/
`uploadAll`/`cancelUpload`/`cancelAllUploads`/`retryUpload`. Without a
`transport`, none of this exists on the returned object, and TypeScript
won't let you call it.

```tsx theme={"theme":{"light":"github-light","dark":"vesper"}}
"use client";

import { useMediaDrop } from "react-mediadrop";
import { createXhrUploadTransport } from "react-mediadrop/xhr-upload";

// Replace with your own upload route.
const transport = createXhrUploadTransport({ endpoint: "/api/upload" });

export function UploadBox() {
	const {
		getRootProps,
		getInputProps,
		files,
		uploadAll,
		cancelUpload,
		retryUpload,
	} = useMediaDrop({
		restrictions: {
			accept: ["image/png", "image/jpeg", "image/webp"],
			maxFiles: 5,
			maxSize: 5 * 1024 * 1024,
		},
		transport,
		concurrency: 3,
		retries: 2,
	});

	return (
		<div {...getRootProps()}>
			<input {...getInputProps()} />

			{files.map((item) => (
				<div key={item.id}>
					{item.name} — {item.uploadStatus ?? "not queued"}
					{item.progress ? ` (${item.progress.loaded} bytes)` : null}
					{item.uploadStatus === "uploading" ? (
						<button type="button" onClick={() => cancelUpload(item.id)}>
							Cancel
						</button>
					) : null}
					{item.uploadStatus === "error" ? (
						<button type="button" onClick={() => retryUpload(item.id)}>
							Retry
						</button>
					) : null}
				</div>
			))}

			<button type="button" onClick={uploadAll}>
				Upload all
			</button>
		</div>
	);
}
```

Click **Upload all**. Each file's status moves from `queued` to
`uploading` to `done` (or `error`, with a Retry button). See
[Upload](/guides/upload) for the full queue/retry/cancel contract.

<CardGroup cols={2}>
  <Card title="Core concepts" icon="cube" href="/guides/core-concepts">
    File model, store, and drag state
  </Card>

  <Card title="Validation" icon="shield-check" href="/guides/validation">
    Restrictions and custom validators
  </Card>

  <Card title="Upload" icon="cloud-arrow-up" href="/guides/upload">
    Queue, concurrency, retry, cancel
  </Card>

  <Card title="useMediaDrop API" icon="code" href="/api-reference/use-media-drop">
    Full hook reference
  </Card>
</CardGroup>
