Open In App

Drag and Drop File Upload Component with React Hooks

Last Updated : 11 Mar, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

In this article, we’re going to delve into creating a drag-and-drop feature for uploading files using React Hooks. Dragging and dropping makes it simple for users to add files to a web app. With React Hooks we can control state and execute actions in components simplifying the management of drag and drop functions. By the conclusion of this guide, you’ll have an operational drag-and-drop file upload component ready for integration, into your React projects.

Output Preview: Let us have a look at how the final output will look like.

Drag-and-Drop

Final output

Prerequisites

Approach to build drag and drop File Upload Component:

  • Utilize drop features with HTML5 drag and drop events
  • Manage file selection and upload by leveraging the FileReader API along, with AJAX requests.
  • Show previews of files using the File API. Incorporate design elements and visual cues to improve user interaction.

Steps to Create the Application:

Step 1: Create a new project by following command

npx create-react-app drag-drop

Step 2: Navigate to the root directory of your project.

cd drag-drop

Folder Structure:

Drag-structure

Structure

Example: Make two files titled Drop-file-input.css and DropFileInput.jsx and place them in a new directory called components in the source folder.

CSS




/* drop-file-input.css */
.drop-file-input {
    position: relative;
    width: 800px;
    height: 400px;
    border: 4px solid var(--border-color);
    border-radius: 20px;
 
    display: flex;
    align-items: center;
    justify-content: center;
 
    background-color: var(--input-bg);
}
 
.drop-file-input input {
    opacity: 0;
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    cursor: pointer;
}
 
.drop-file-input:hover,
.drop-file-input.dragover {
    opacity: 0.6;
}
 
.drop-file-input__label {
    text-align: center;
    color: var(--txt-second-color);
    font-weight: 600;
    padding: 10px;
}
 
.drop-file-input__label img {
    width: 100px;
}
 
.drop-file-preview {
    margin-top: 30px;
}
 
.drop-file-preview p {
    font-weight: 500;
}
 
.drop-file-preview__title {
    margin-bottom: 20px;
}
 
.drop-file-preview__item {
    position: relative;
    display: flex;
    margin-bottom: 10px;
    background-color: var(--input-bg);
    padding: 15px;
    border-radius: 20px;
}
 
.drop-file-preview__item img {
    width: 50px;
    margin-right: 20px;
}
 
.drop-file-preview__item__info {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
}
 
.drop-file-preview__item__del {
    background-color: var(--box-bg);
    width: 40px;
    height: 40px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    position: absolute;
    right: 10px;
    top: 50%;
    transform: translateY(-50%);
    box-shadow: var(--box-shadow);
    cursor: pointer;
    opacity: 0;
    transition: opacity 0.3s ease;
}
 
.drop-file-preview__item:hover .drop-file-preview__item__del {
    opacity: 1;
}


CSS




/* App.css */
 
:root {
    --body-bg: #f5f8ff;
    --box-bg: #fff;
    --input-bg: #f5f8ff;
    --txt-color: #2f2d2f;
    --txt-second-color: #ccc;
    --border-color: #31c503;
    --box-shadow: rgba(149, 157, 165, 0.2) 0px 8px 24px;
}
 
* {
    padding: 0;
    margin: 0;
    box-sizing: border-box;
}
 
body {
    font-family: "Monospace", sans-serif;
    font-weight: 400;
    line-height: 1.5;
    background-color: var(--body-bg);
    color: var(--txt-color);
 
    display: flex;
    justify-content: center;
    padding-top: 100px;
 
    height: 100vh;
}
 
.box {
    background-color: var(--box-bg);
    padding: 30px;
    border-radius: 20px;
    box-shadow: var(--box-shadow);
}
 
.header {
    margin-bottom: 30px;
    text-align: center;
}


Javascript




//App.js
import './App.css';
import DropFileInput from './components/drop-file-input/DropFileInput.js';
 
function App() {
    const onFileChange = (files) => {
        console.log(files);
    }
    return (
        <div className="box">
            <h2 className="header">
                React drop files input
            </h2>
            <DropFileInput
                onFileChange={(files) => onFileChange(files)}
            />
        </div>
    );
}
 
export default App;


Javascript

Javascript




// DropFileInput.jsx
import React, { useRef, useState } from 'react';
import PropTypes from 'prop-types';
import './drop-file-input.css';
import { ImageConfig } from '../../config/ImageConfig.js';
 
const DropFileInput = props => {
 
    const wrapperRef = useRef(null);
 
    const [fileList, setFileList] = useState([]);
 
    const onDragEnter = () => wrapperRef.current.classList.add('dragover');
 
    const onDragLeave = () => wrapperRef.current.classList.remove('dragover');
 
    const onDrop = () => wrapperRef.current.classList.remove('dragover');
 
    const onFileDrop = (e) => {
        const newFile = e.target.files[0];
        if (newFile) {
            const updatedList = [...fileList, newFile];
            setFileList(updatedList);
            props.onFileChange(updatedList);
        }
    }
 
    const fileRemove = (file) => {
        const updatedList = [...fileList];
        updatedList.splice(fileList.indexOf(file), 1);
        setFileList(updatedList);
        props.onFileChange(updatedList);
    }
 
    return (
        <>
            <div
                ref={wrapperRef}
                className="drop-file-input"
                onDragEnter={onDragEnter}
                onDragLeave={onDragLeave}
                onDrop={onDrop}
            >
                <div className="drop-file-input__label">
                    <img src={"https://media.geeksforgeeks.org/wp-content/uploads/20240308113922/Drag-.png"}
                        alt="" />
                    <p>Drag & Drop your files here</p>
                </div>
                <input type="file" value="" onChange={onFileDrop} />
            </div>
            {
                fileList.length > 0 ? (
                    <div className="drop-file-preview">
                        <p className="drop-file-preview__title">
                            Ready to upload
                        </p>
                        {
                            fileList.map((item, index) => (
                                <div key={index} className="drop-file-preview__item">
                                    <img src={ImageConfig[item.type.split('/')[1]] ||
                                        ImageConfig['default']} alt="" />
                                    <div className="drop-file-preview__item__info">
                                        <p>{item.name}</p>
                                        <p>{item.size}B</p>
                                    </div>
                                    <span className="drop-file-preview__item__del"
                                        onClick={() => fileRemove(item)}>
                                        x
                                    </span>
                                </div>
                            ))
                        }
                    </div>
                ) : null
            }
        </>
    );
}
 
DropFileInput.propTypes = {
    onFileChange: PropTypes.func
}
 
export default DropFileInput;


Start your application using the following command.

npm start

Output:

ezgif-4-81478569a0

Drag and Drop File Upload Component with React Hooks



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads