Dropzone

Capture files from user with drag and drop
Import
License

Installation

Package depends on @mantine/core and @mantine/hooks.

Install with npm:

npm install @mantine/dropzone @mantine/core @mantine/hooks

Install with yarn:

yarn add @mantine/dropzone @mantine/core @mantine/hooks

Usage

Dropzone lets you capture one or more files from user. Component is built with react-dropzone and support all of its core features:

  • Accepts/rejects files based on provided mime types
  • Limits individual file size
  • Renders any content within dropzone with children function
Drag images here or click to select files
Attach as many files as you like, each file should not exceed 5mb
import { Group, Text, useMantineTheme, MantineTheme } from '@mantine/core';
import { Upload, Photo, X, Icon as TablerIcon } from 'tabler-icons-react';
import { Dropzone, DropzoneStatus, IMAGE_MIME_TYPE } from '@mantine/dropzone';
function getIconColor(status: DropzoneStatus, theme: MantineTheme) {
return status.accepted
? theme.colors[theme.primaryColor][theme.colorScheme === 'dark' ? 4 : 6]
: status.rejected
? theme.colors.red[theme.colorScheme === 'dark' ? 4 : 6]
: theme.colorScheme === 'dark'
? theme.colors.dark[0]
: theme.colors.gray[7];
}
function ImageUploadIcon({
status,
...props
}: React.ComponentProps<TablerIcon> & { status: DropzoneStatus }) {
if (status.accepted) {
return <Upload {...props} />;
}
if (status.rejected) {
return <X {...props} />;
}
return <Photo {...props} />;
}
export const dropzoneChildren = (status: DropzoneStatus, theme: MantineTheme) => (
<Group position="center" spacing="xl" style={{ minHeight: 220, pointerEvents: 'none' }}>
<ImageUploadIcon status={status} style={{ color: getIconColor(status, theme) }} size={80} />
<div>
<Text size="xl" inline>
Drag images here or click to select files
</Text>
<Text size="sm" color="dimmed" inline mt={7}>
Attach as many files as you like, each file should not exceed 5mb
</Text>
</div>
</Group>
);
function Demo() {
const theme = useMantineTheme();
return (
<Dropzone
onDrop={(files) => console.log('accepted files', files)}
onReject={(files) => console.log('rejected files', files)}
maxSize={3 * 1024 ** 2}
accept={IMAGE_MIME_TYPE}
>
{(status) => dropzoneChildren(status, theme)}
</Dropzone>
);
}

Loading state

Set loading prop to indicate loading state with LoadingOverlay component. When loading is set to true user cannot drop or select new files (Dropzone becomes disabled):

Drag images here or click to select files
Attach as many files as you like, each file should not exceed 5mb
import { Dropzone } from '@mantine/dropzone';
function Demo() {
return (
<Dropzone loading>
{/* children */}
</Dropzone>
);
}

Disabled state

If you want to implement your own loading state you can disable Dropzone without LoadingOverlay. Same as with loading, when Dropzone is disabled user user cannot drop or select new files:

Drag images here or click to select files
Attach as many files as you like, each file should not exceed 5mb
import { createStyles } from '@mantine/core';
import { Dropzone } from '@mantine/dropzone';
// Add your own disabled styles
const useStyles = createStyles((theme) => ({
disabled: {
backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[6] : theme.colors.gray[0],
borderColor: theme.colorScheme === 'dark' ? theme.colors.dark[5] : theme.colors.gray[2],
cursor: 'not-allowed',
'& *': {
color: theme.colorScheme === 'dark' ? theme.colors.dark[3] : theme.colors.gray[5],
},
},
}));
function Demo() {
const { classes } = useStyles();
return (
<Dropzone disabled className={classes.disabled}>
{/* children, see previous demo */}
</Dropzone>
);
}

Open file browser manually

To open files browser from outside of component use openRef prop to get function that will trigger file browser:

Drag images here or click to select files
Attach as many files as you like, each file should not exceed 5mb
import { useRef } from 'react';
import { Button, Group } from '@mantine/core';
import { Dropzone } from '@mantine/dropzone';
function Demo() {
const openRef = useRef<() => void>();
return (
<>
<Dropzone openRef={openRef}>
{/* children */}
</Dropzone>
<Group position="center" mt="md">
<Button onClick={() => openRef.current()}>Select files</Button>
</Group>
</>
);
}

Mime types

To specify specific file types provide an array of mime types to accept prop:

import { Dropzone } from '@mantine/dropzone';
function Demo() {
return (
<Dropzone accept={['image/png', 'image/jpeg', 'image/sgv+xml', 'image/gif']}>
{/* children */}
</Dropzone>
);
}

To save some research time you can use MIME_TYPES variable exported from @mantine/dropzone:

import { Dropzone, MIME_TYPES } from '@mantine/dropzone';
function Demo() {
return (
<Dropzone accept={[MIME_TYPES.png, MIME_TYPES.jpeg, MIME_TYPES.svg, MIME_TYPES.gif]}>
{/* children */}
</Dropzone>
);
}

MIME_TYPES includes following data:

KeyMime type
pngimage/png
gifimage/gif
jpegimage/jpeg
svgimage/svg+xml
webpimage/webp
mp4video/mp4
zipapplication/zip
csvtext/csv
pdfapplication/pdf
docapplication/msword
docxapplication/vnd.openxmlformats-officedocument.wordprocessingml.document
xlsapplication/vnd.ms-excel
xlsxapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheet
pptapplication/vnd.ms-powerpoint
pptxapplication/vnd.openxmlformats-officedocument.presentationml.presentation
exeapplication/vnd.microsoft.portable-executable

Additionally you can use grouped mime types:

VariableMime types
IMAGE_MIME_TYPEimage/png, image/gif, image/jpeg, image/svg+xml, image/webp
PDF_MIME_TYPEapplication/pdf
MS_WORD_MIME_TYPEapplication/msword, application/vnd.openxmlformats-officedocument.wordprocessingml.document
MS_EXCEL_MIME_TYPEapplication/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
MS_POWERPOINT_MIME_TYPEapplication/vnd.ms-powerpoint, application/vnd.openxmlformats-officedocument.presentationml.presentation
import { IMAGE_MIME_TYPE, Dropzone } from '@mantine/dropzone';
function Demo() {
return <Dropzone accept={IMAGE_MIME_TYPE}>{/* children */}</Dropzone>;
}

Get ref

import { useRef, useEffect } from 'react';
import { Dropzone } from '@mantine/dropzone';
function Demo() {
const dropzoneRef = useRef<HTMLDivElement>();
useEffect(() => {
dropzoneRef.current.focus();
}, []);
return <Dropzone ref={dropzoneRef}>{/* children */}</Dropzone>;
}

FullScreenDropzone component

FullScreenDropzone lets you capture files dropped to browser window instead of specific area. Component is built without react-dropzone (due to some bugs in mime types detections) but supports the same props and features as Dropzone component shown above (except maxSize, onReject, openRef and loading props).

To preview component click button and drop images to browser window:

import { useState } from 'react';
import { Button } from '@mantine/core';
import { FullScreenDropzone, IMAGE_MIME_TYPE } from '@mantine/dropzone';
function Demo() {
const [disabled, setDisabled] = useState(true);
return (
<>
<Button color={disabled ? 'blue' : 'red'} onClick={() => setDisabled((d) => !d)}>
{disabled ? 'Enable' : 'Disable'} full screen dropzone
</Button>
<FullScreenDropzone
disabled={disabled}
accept={IMAGE_MIME_TYPE}
onDrop={(files) => {
console.log(files);
setDisabled(true);
}}
>
{/* See dropzone children in previous demo */}
</FullScreenDropzone>
</>
);
}