joplin-notes/joplin notion extension/Web Development/React/Snippets/Drag and Drop File Upload.md
2026-11-04 00:33:23 +05:30

9.1 KiB

Drag and Drop File Upload

react-drop-file-input-main.zip

  • JSX

    import React, { useRef, useState } from 'react';
    import PropTypes from 'prop-types';
    
    import './drop-file-input.css';
    
    import { ImageConfig } from '../../config/ImageConfig'; 
    import uploadImg from '../../assets/cloud-upload-regular-240.png';
    
    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={uploadImg} 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;
    

     
    CSS

    .drop-file-input {
        position: relative;
        width: 400px;
        height: 200px;
        border: 2px dashed 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;
    }
    

     

  • For multiple file uploading use this and to limit the height of preview file list:

    import React, { useRef, useState } from "react";
      import PropTypes from "prop-types";
    
      import "./drop-file-input.css";
    
      import { ImageConfig } from "../../config/ImageConfig";
      import uploadImg from "../../assets/cloud-upload-regular-240.png";
    
      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 newFiles = e.target.files;
      	if (newFiles.length !== 0) {
      	  const updatedList = [...fileList, ...newFiles];
      	  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={uploadImg} alt="" />
      		  <p>Drag & Drop your files here</p>
      		</div>
      		<input type="file" value="" multiple 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;
    
    

      CSS

    .drop-file-input {
    position: relative;
    width: 400px;
    height: 200px;
    border: 2px dashed 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;
        max-height: 70%;
        overflow-y: auto;
      }
    
      .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;
      }