9.1 KiB
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; }