Open In App

Drag and Drop File Upload Component with React Hooks

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.



Final output

Prerequisites

Approach to build drag and drop File Upload Component:

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:

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.




/* 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;
}




/* 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;
}




//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;




// 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:

Drag and Drop File Upload Component with React Hooks


Article Tags :