In this tutorial, we’ll see how to add drag and drop image file upload with preview in React with Tailwind CSS and Dropzone. Before you begin, ensure your project has React, TypeScript, and Tailwind CSS installed and configured.
Run below command to install dropzone in react project.
npm install --save react-dropzone
# or:
yarn add react-dropzone
Build an easy drag-and-drop system for uploading images with a preview using the React Dropzone library. Make it happen using React’s useCallback and useState hooks, and style it up with Tailwind CSS.
import { useCallback, useState } from 'react';
import { useDropzone } from 'react-dropzone';
const ImageUpload = () => {
const [selectedImage, setSelectedImage] = useState(null);
const onDrop = useCallback(acceptedFiles => {
const image = acceptedFiles[0];
const reader = new FileReader();
reader.onload = () => {
setSelectedImage(reader.result);
};
reader.readAsDataURL(image);
}, []);
const { acceptedFiles, getRootProps, getInputProps } = useDropzone({
onDrop,
accept: {
'image/*': []
},
multiple: false,
});
console.log('Accepted Files:', acceptedFiles);
return (
<div className="flex items-center justify-center h-screen">
<div className="bg-white p-8 rounded-lg shadow-md">
<div {...getRootProps()} className="dropzone text-center border-dashed border-2 border-gray-300 p-6 rounded-md">
<input {...getInputProps()} />
<p className="text-gray-600">Drag 'n' drop an image here, or click to select one</p>
</div>
{selectedImage && (
<div className="mt-4">
<h2 className="text-xl font-semibold mb-2">Selected Image</h2>
<img src={selectedImage} alt="Selected" className="max-w-full rounded-md" />
</div>
)}
</div>
</div>
);
};
export default ImageUpload;
Create a quick drag-and-drop image uploader with preview using React, TypeScript, and the React Dropzone library. Style it with Tailwind CSS for a polished look.
import { useCallback, useState, FC } from 'react';
import { useDropzone, DropzoneRootProps, DropzoneInputProps, DropzoneState } from 'react-dropzone';
interface ImageUploadProps {
// Add any additional props here
}
const ImageUpload: FC<ImageUploadProps> = () => {
const [selectedImage, setSelectedImage] = useState<string | null>(null);
const onDrop = useCallback((acceptedFiles: File[]) => {
const image = acceptedFiles[0];
const reader = new FileReader();
reader.onload = () => {
setSelectedImage(reader.result as string);
};
reader.readAsDataURL(image);
}, []);
const {
acceptedFiles,
getRootProps,
getInputProps,
}: {
acceptedFiles: File[];
} & DropzoneRootProps & DropzoneInputProps & DropzoneState = useDropzone({
onDrop,
accept: {
'image/*': []
},
multiple: false,
});
console.log('Accepted Files:', acceptedFiles);
return (
<div className="flex items-center justify-center h-screen">
<div className="bg-white p-8 rounded-lg shadow-md">
<div {...getRootProps()} className="dropzone text-center border-dashed border-2 border-gray-300 p-6 rounded-md">
<input {...getInputProps()} />
<p className="text-gray-600">Drag 'n' drop an image here, or click to select one</p>
</div>
{selectedImage && (
<div className="mt-4">
<h2 className="text-xl font-semibold mb-2">Selected Image</h2>
<img src={selectedImage} alt="Selected" className="max-w-full rounded-md" />
</div>
)}
</div>
</div>
);
};
export default ImageUpload;
Build a quick drag-and-drop image uploader with multiple file support and live previews using React, TypeScript, and Tailwind CSS.
import { useCallback, useState, FC } from 'react';
import { useDropzone, DropzoneRootProps, DropzoneInputProps, DropzoneState } from 'react-dropzone';
interface ImageUploadProps {
// Add any additional props here
}
const ImageUpload: FC<ImageUploadProps> = () => {
const [selectedImages, setSelectedImages] = useState<string[]>([]);
const onDrop = useCallback((acceptedFiles: File[]) => {
// Do something with the uploaded images, for example, display them.
const imagePromises: Promise<string>[] = acceptedFiles.map((image) => {
return new Promise((resolve) => {
const reader = new FileReader();
reader.onload = () => {
resolve(reader.result as string);
};
reader.readAsDataURL(image);
});
});
Promise.all(imagePromises).then((results) => {
setSelectedImages(results);
});
}, []);
const {
acceptedFiles,
getRootProps,
getInputProps,
}: {
acceptedFiles: File[];
} & DropzoneRootProps & DropzoneInputProps & DropzoneState = useDropzone({
onDrop,
accept: {
'image/*': []
},
multiple: true,
});
console.log('Accepted Files:', acceptedFiles);
return (
<div className="flex items-center justify-center h-screen">
<div className="bg-white p-8 rounded-lg shadow-md">
<div {...getRootProps()} className="dropzone text-center border-dashed border-2 border-gray-300 p-6 rounded-md">
<input {...getInputProps()} />
<p className="text-gray-600">Drag 'n' drop images here, or click to select</p>
</div>
{selectedImages.length > 0 && (
<div className="mt-4">
<h2 className="text-xl font-semibold mb-2">Selected Images</h2>
<div className="flex flex-wrap">
{selectedImages.map((image, index) => (
<img key={index} src={image} alt={`Selected ${index + 1}`} className="max-w-full rounded-md m-2" />
))}
</div>
</div>
)}
</div>
</div>
);
};
export default ImageUpload;
Sources
- react useState (react.dev)
- react useEffect (react.dev)
- react useCallback (react.dev)
- Tailwind CSS (tailwindcss.com)
- typescriptlang.org
- react-dropzone.js.org