Build A React Drag & Drop Progress File Uploader

In-Depth Walkthrough On How To Make A Drag & Drop File Uploader That Shows Its Upload Progress In React

Manny
17 min readAug 12, 2019
How To Build A React Drag & Drop Progress File Uploader

What Are We Building

If you have ever seen a progress file uploader that exists online, like Google Drive, or other major web application, that is essential what we’re building today, but with a simpler UI, and in React.

Example Google Drive File Progress Uploader

Why Do This?

One of the main reasons to build this is to give users more context in terms of the state they are currently in, their progress, and give them more options while they are uploading files.

What I mean by this is that when you’re building a Minimal Viable Product web application, typically what happens is that the user is given a choice to just upload a file. Once the file is uploading, they are usually presented with a loader (like below), and have to wait until that file is done uploading to proceed with the next step. What we want to do is take this further and give the user a progress update, and even allow them to abort the process all-together.

SVG Loaders by Sam Herbert

Requirements

Before we start, the only thing that you need is the following to make sure you can get through everything.

  • NodeJS 10.16.1
  • Browser That Support FileAPI with FileReader

Step 1 — Backend API File Uploader

Before we can even create our frontend, we need to have a backend that accepts file uploads, for this we’ll make a simple Backend API that accepts files with a POST endpoint in NodeJS.

Create New NodeJS Project

# create new folder
mkdir uploadapi;

# enter folder
cd uploadd api;

# create new file
touch index.js;
# create files directory
mkdir files;

# init
yarn init -y; # or npm init -y;

Install Dependencies

We’re going to use express for the endpoints and multiparty for handling the form data.

yarn add express; # npm install express;

yarn add multiparty; # npm install multiparty; # to handle form data

yarn add cors; # npm install cors; # allow requests from other ports

Create Application

Let’s create our NodeJS application:

File: /uploadapi/index.js

// Imports
const express = require('express');
const multiparty = require('multiparty');
const app = express();
const port = 5000;
const cors = require('cors');
const fs = require('fs');
const folder = 'files/';
// CORS configurations
app.use(cors());
// Endpoints
app.post('/upload', (req, res) => {
// initiate multiparty
const form = new multiparty.Form();

// parse req form data
return form.parse(req, (err, fields, files) => {
// error handling
if (err) {
return res.status(400).send({error: err });
}

// path
const { path } = files.file[0];

// get the temp file name from the tmp folder
let filename = path.split('/');
filename = filename[filename.length - 1];

// move file into folder
return fs.rename(path, `${folder}${filename}`, error => {
// error handling for moving
if (error) {
return res.status(400).send({ error });
}
return res.status(200).send({ file: filename });
});
});
});
// Listen
app.listen(port, () => console.log(`Listening on port ${port}`));

Test File Upload With Postman

Now that we have our file, let’s start our server up and test a file upload with Postman.

Start our server up with:

node index.js# Expected output
# Listening on port 5000

Open up Postman, and make sure the settings are set as follows:

POST http://localhost:5000/uploadBody: form-data
key: file
value: youfile.png
Postman Uploading File
VSCode showing new file created in /files folder

Step 2—Create React App

Now that we have our backend setup, we need to scaffold out our React frontend with create-react-app:

Create A New Project Folder

# create new directory
mkdir react-uploader;
# scaffold out create-react-app
npx create-react-app react-uploader;

Remove Unnecessary Files

# Remove files
rm react-uploader/src/App.css;
rm react-uploader/src/App.js;
rm react-uploader/src/App.test.js;
rm react-uploader/src/logo.svg;
rm react-uploader/src/index.css;
# Create blank file
touch react-uploader/src/App.js;
touch react-uploader/src/index.css;

Step 3— Creating Our UI

The way we’re going to create our UI is that we’re going to have a drop area that will accept a file, show a preview (if it’s an image), and have a progress percentage display in the middle.

If we break this up into components, we should have something like this:

- App
- ImagePreview
- DropArea
- ImageStatus
- Status

Creating Our Main Component

Our main structure for our App.js should be pretty simple:

File: /react-uploader/src/App.js

import React from 'react';const App = () => {
return (
<div className="App">
</div>
);
};
export default App;

We might just want to modify our index.css file to adjust for the default browser margins and padding:

File: /react-uploader/src/index.css

html, body {
margin: 0;
padding: 0;
width: 100vw;
height: 100vh;
}

We also wanted to make sure our child div for the App is centered with Flexbox:
File: /react-uploader/src/index.css

html, body {
margin: 0;
padding: 0;
width: 100vw;
height: 100vh;
}
.App {
display: flex;
align-items: center;
justify-content: center;
width: 100vw;
height: 100vh;
}

Create DropArea & Status Component

Next let’s create our drop area and make it slightly smaller than main App and add some transparent borders to it to start, so that we can account for their width when we add a hover effect to make the border a color.

File: /react-uploader/src/App.js

import React from 'react';const App = () => {
return (
<div className="App">
<div className="DropArea">
<div className="Status">Drop Here</div>
</div>
</div>
);
};
export default App;

File: /react-uploader/src/index.css

html, body {
margin: 0;
padding: 0;
width: 100vw;
height: 100vh;
}
.App {
display: flex;
align-items: center;
justify-content: center;
width: 100vw;
height: 100vh;
}
.DropArea {
background: #efefef;
display: flex;
align-items: center;
justify-content: center;
width: calc(80vw - 80px);
height: calc(80vh - 80px);
border: solid 40px transparent;
transition: all 250ms ease-in-out 0s;
position: relative;

}
.Status {
background: transparent;
display: block;
font-family: 'Helvetica', Arial, sans-serif;
color: black;
font-size: 60px;
font-weight: bold;
text-align: center;
line-height: calc(80vh - 80px);
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
transition: all 250ms ease-in-out 0s;
}

If we take a look at our project so far it should look like below:

React File Uploader Progress

ImageStatus Component

Next, what I want to do here is place an image in the middle to show the image we’re currently uploading as a preview. We’re going to use this image from Unsplash, well, because I love Montreal. We’ll place it in the same directory as our react project.

Jacque Cartier Bridge by Eva Blue

In our App.js we’ll create our new div with a sub div to hold the image.

File: /react-uploader/src/App.js

import React from 'react';
import BgImage from './eva-blue-unsplash.jpg';
const App = () => {
return (
<div className="App">
<div className="ImagePreview">
<div style={{ backgroundImage: `url(${BgImage})` }} />
</div>

<div className="DropArea">
<div className="Status">Drop Here</div>
</div>
</div>
);
};
export default App;

Next, we’ll modify the css to make our background image cover the entire background and give it a blurred look:

File: /react-uploader/src/index.css

....App {
background-size: cover;
display: flex;
align-items: center;
justify-content: center;
width: 100vw;
height: 100vh;
}
.ImagePreview {
display: block;
left: 0;
right: 0;
bottom: 0;
top: 0;
position: absolute;
overflow: hidden;
}
.ImagePreview > div {
position: absolute;
background-size: cover;
filter: blur(20px);
left: -40px;
right: -40px;
bottom: -40px;
top: -40px;
}
...

We should get the following:

React File Uploader — Preview Image

I also want to be able to show a progress of the image being uploaded with its physical size, but using a mask. To do this, we’ll use two image placed over top of one another.

File: /react-uploader/src/App.js

import React from 'react';
import BgImage from './eva-blue-unsplash.jpg';
const App = () => {
return (
<div className="App">
<div className="ImagePreview">
<div style={{ backgroundImage: `url(${BgImage})` }}></div>
</div>
<div className="DropArea">
<div className="ImageProgress">
<div className="ImageProgressImage" style={{ backgroundImage: `url(${BgImage})` }}></div>
<div className="ImageProgressUploaded" style={{ backgroundImage: `url(${BgImage})` }}></div>
</div>

<div className="Status">Drop Here</div>
</div>
</div>
);
};
export default App;

In the css file, we’ll simulate the progress using clip-path.

File: /react-uploader/src/index.css

....DropArea {
background: #efefef;
display: flex;
align-items: center;
justify-content: center;
width: calc(80vw - 80px);
height: calc(80vh - 80px);
border: solid 40px transparent;
transition: all 250ms ease-in-out 0s;
position: relative;
}
.ImageProgress {
display: block;
left: 0;
right: 0;
top: 0;
bottom: 0;
position: absolute;
overflow: hidden;
}
.ImageProgress > .ImageProgressImage {
opacity: 0.3;
position: absolute;
background-position: center center;
background-size: cover;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.ImageProgress > .ImageProgressUploaded {
position: absolute;
background-position: center center;
background-size: cover;
top: 0;
left: 0;
right: 0;
bottom: 0;
clip-path: inset(50% 0 0 0);
}
...

If we save our work, we should something like the following:

React File Uploader — Image Upload Progress UI

Let’s make a slight adjustment to make the “Drop Here” text more visible with the image. We’ll give it a background with a semi-transparent black and white text instead.

File: /react-uploader/src/index.js

....Status {
background: rgba(0, 0, 0, 0.3);
display: block;
font-family: 'Helvetica', Arial, sans-serif;
color: white;
font-size: 60px;
font-weight: bold;
text-align: center;
line-height: calc(80vh - 80px);
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
transition: all 250ms ease-in-out 0s;
}
React File Uploader — Image Upload Progress UI Revised

Step 4— File Preview

Now we have all our UI elements created, it’s time to add the functionality of things. We need to create event handlers for dragging and dropping a file, handling only images, and then reading that file with FileReader.

Temporary Clean Up

We first need to get our divs in the original state, so we’re just going to comment them out in the meantime.

File: /react-uploader/src/App.js

import React from 'react';const App = () => {
return (
<div className="App">
{/* <div className="ImagePreview">
<div style={{ backgroundImage: `url(${BgImage})` }}> </div>
</div> */}

<div className="DropArea">
{/* <div className="ImageProgress">
<div className="ImageProgressImage" style={{ backgroundImage: `url(${BgImage})` }}></div>
<div className="ImageProgressUploaded" style={{ backgroundImage: `url(${BgImage})` }}></div>
</div> */}

<div className="Status">Drop Here</div>
</div>
</div>
);
};
export default App;

We also want to reset our status background and color:

File: /react-uploader/src/index.css

.Status {
background: transparent;
display: block;
font-family: 'Helvetica', Arial, sans-serif;
color: black;
font-size: 60px;
font-weight: bold;
text-align: center;
line-height: calc(80vh - 80px);
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
transition: all 250ms ease-in-out 0s;
}
React File Uploader — Reset State

Creating Drag & Drop Handlers

Next, we’ll create event handlers on the main div className="App" so that it can know when a file has been dragged to the window.

File: /react-uploader/src/App.js

...const App = () => {
const onDragEnter = event => {
console.log(event);
event.preventDefault();
}
return (
<div className="App" onDragEnter={onDragEnter}>
...

Now we if drag a file to our window (REMEMBER NOT TO DROP IT), you’ll see the event fired:

React File Uploader — DragEnter Event Fired

Next, we’ll use useState to manage the status message to give the user feedback as when a file has been detected.

File: /react-uploader/src/App.js

import React, { useState } from 'react';
import BgImage from './eva-blue-unsplash.jpg';
const App = () => {
const [status, setStatus] = useState('Drop Here');
const onDragEnter = event => {
console.log(event);
setStatus('File Detected');
event.preventDefault();
}
...
<div className="Status">{status}</div>
</div>
</div>
);
};
export default App;
React File Uploader — DragEnter Status Changed

We also need to handle with the file dragging has left the window:

File: /react-uploader/src/App.js

...    const onDragEnter = event => {
setStatus('File Detected');
event.preventDefault();
}
const onDragLeave = event => {
setStatus('Drop Here');
event.preventDefault();
}
return (
<div className="App" onDragEnter={onDragEnter} onDragLeave={onDragLeave}>
...

Now we’ll add a drag over event, with a twist to the css animation, and a drop event to start the process of reading the file.

File: /react-uploader/src/App.js

...    const onDragEnter = event => {
setStatus('File Detected');
event.preventDefault();
event.stopPropagation();
}
const onDragLeave = event => {
setStatus('Drop Here');
event.preventDefault();
}
const onDragOver = event => {
setStatus('Drop');
event.preventDefault();
}
const onDrop = event => {
console.log(event);
event.preventDefault();
}
...<div className={`DropArea ${status === 'Drop' ? 'Over' : ''}`} onDragOver={onDragOver} onDrop={onDrop} onDragLeave={onDragEnter}>

and modify our css:

File: /react-uploader/src/index.css

....DropArea {
background: #efefef;
display: flex;
align-items: center;
justify-content: center;
width: calc(80vw - 80px);
height: calc(80vh - 80px);
border: solid 40px transparent;
transition: all 250ms ease-in-out 0s;
position: relative;
}
.DropArea.Over {
border: solid 40px rgba(0, 0, 0, 0.2);
}
...

Now while dragging we’ll see the following states:

React File Uploader — Drag States

Fixing onDrop Event For App Component

You’ll notice that if we drop the file too soon on the App area it will load the image. We’ll fix this with a event.preventDefault().

File: /react-uploader/src/App.js

...const App = () => {
const [status, setStatus] = useState('Drop Here');
const doNothing = event => event.preventDefault();...
<div className="App" onDragEnter={onDragEnter} onDragLeave={onDragLeave} onDragOver={doNothing} onDrop={onDragLeave}>

Not when we drop the file on the className="App" area, nothing happens and it resets as it should.

Detecting Supported File

We can now read the file when the file is dropped in the DropArea by reading the event.

File: /react-uploader/src/App.js

const onDrop = event => {
const supportedFilesTypes = ['image/jpeg', 'image/png'];
const { type } = event.dataTransfer.files[0];
if (supportedFilesTypes.indexOf(type) > -1) {
// continue with code
}

event.preventDefault();
};

Reading File

Now that we can confirm that a file is an image, we can read the file and set it for a new state called preview.

File: /react-uploader/src/App.js

...const App = () => {
const [status, setStatus] = useState('Drop Here');
const [preview, setPreview] = useState(null);
...const onDrop = event => {
const supportedFilesTypes = ['image/jpeg', 'image/png'];
const { type } = event.dataTransfer.files[0];
if (supportedFilesTypes.indexOf(type) > -1) {
// Begin Reading File
const reader = new FileReader();
reader.onload = e => setPreview(e.target.result);
reader.readAsDataURL(event.dataTransfer.files[0]);

}
event.preventDefault();
};
...

Displaying File

To display the image that we just dropped, we’ll use the preview state in our component.

File: /react-uploader/src/App.js

...<div className="App" onDragEnter={onDragEnter} onDragLeave={onDragLeave} onDragOver={doNothing} onDrop={onDragLeave}>
<div className={`ImagePreview ${preview ? 'Show' : ''}`}>
<div style={{ backgroundImage: `url(${preview})` }}></div>
</div>
<div className={`DropArea ${status === 'Drop' ? 'Over' : ''}`} onDragOver={onDragOver} onDragLeave={onDragEnter} onDrop={onDrop}>
<div className={`ImageProgress ${preview ? 'Show' : ''}`}>
<div className="ImageProgressImage" style={{ backgroundImage: `url(${preview})` }}></div>
<div className="ImageProgressUploaded" style={{ backgroundImage: `url(${preview})` }}></div>
</div>
<div className="Status">{status}</div>
</div>
</div>
...

To add a bit of smoother animation, we’ll modify our css file to add a transition.

File: /react-uploader/src/index.css

...

.ImagePreview {
opacity: 0;
display: block;
left: 0;
right: 0;
bottom: 0;
top: 0;
position: absolute;
overflow: hidden;
transition: all 500ms ease-in-out 250ms;
}
.ImagePreview.Show {
opacity: 1;
}
....ImageProgress {
opacity: 0;
display: block;
left: 0;
right: 0;
top: 0;
bottom: 0;
position: absolute;
overflow: hidden;
transition: all 500ms ease-in-out 250ms;
}
.ImageProgress.Show {
opacity: 1;
}
...

When you load it, you should get that smooth fade-in with the image.

React File Uploader — Animation

Step 5— Uploading File

Now that we can read the file, we can now also upload the file to our backend server with a progress update. For this though we’re doing to use an XMLHttpRequest.

Why Not Fetch?

Unfortunately Fetch does not have an event handle for upload progress, that’s why we’ll be using XHR instead, which has more event handlers, aka more options.

Uploading The File

To start we’re just going to upload the file normally to make sure that it can communicate with our backend.

File: /react-uploader/src/App.js

...
const onDrop = event => {
const supportedFilesTypes = ['image/jpeg', 'image/png'];
const { type } = event.dataTransfer.files[0];
if (supportedFilesTypes.indexOf(type) > -1) {
// Begin Reading File
const reader = new FileReader();
reader.onload = e => setPreview(e.target.result);
reader.readAsDataURL(event.dataTransfer.files[0]);
// Create Form Data
const payload = new FormData();
payload.append('file', event.dataTransfer.files[0]);
// XHR - New XHR Request
const xhr = new XMLHttpRequest();
// XHR - Make Request
xhr.open('POST', '
http://localhost:5000/upload');
xhr.send(payload);

}
event.preventDefault();
};
...

Now if you drag and drop an image to the drop area, you’ll see that the file gets successfully sent to your backend.

React File Uploader — Successfully Uploaded

Step 6— XHR Events

Next we’re going to take advantage of an event that gets fired as our file gets progressively uploaded. This is with .upload.onprogress. We’ll take advantage of this to both display the percentage as well as display the percentage in visual way.

File: /react-uploader/src/App.js

...const App = () => {
const [status, setStatus] = useState('Drop Here');
const [percentage, setPercentage] = useState(0);
... const onDrop = event => {
const supportedFilesTypes = ['image/jpeg', 'image/png'];
const { type } = event.dataTransfer.files[0];
if (supportedFilesTypes.indexOf(type) > -1) {
// Begin Reading File
const reader = new FileReader();
reader.onload = e => setPreview(e.target.result);
reader.readAsDataURL(event.dataTransfer.files[0]);
// Create Form Data
const payload = new FormData();
payload.append('file', event.dataTransfer.files[0]);
// XHR - New XHR request
const xhr = new XMLHttpRequest();
// XHR - Upload Progress
xhr.upload.onprogress = (e) => {
const done = e.position || e.loaded
const total = e.totalSize || e.total;
const perc = (Math.floor(done/total*1000)/10);
if (perc >= 100) {
setStatus('Done');
} else {
setStatus(`${perc}%`);
}
setPercentage(perc);
};
// XHR - Make Request
xhr.open('POST', 'http://localhost:5000/upload');
xhr.send(payload);
}
event.preventDefault();
};
...

We’re also going to modify our upload progress image to reflect this new percentage state.

File: /react-uploader/src/App.js

...
<div className={`ImageProgress ${preview ? 'Show' : ''}`}>
<div className="ImageProgressImage" style={{ backgroundImage: `url(${preview})` }}></div>
<div className="ImageProgressUploaded" style={{ backgroundImage: `url(${preview})`, clipPath: `inset(${100 - Number(percentage)}% 0 0 0);` }}></div>
</div>
...

and modify that css from our stylesheet to set an initial state and add a transition for smoother movement:

File: /react-uploader/src/index.css

....ImageProgress > .ImageProgressUploaded {
position: absolute;
background-position: center center;
background-size: cover;
top: 0;
left: 0;
right: 0;
bottom: 0;
clip-path: inset(0% 0 0 0);
transition: all 250ms ease-in-out 0ms;

}
...

If you try and drag and drop a file, the upload my happen really quickly because the server connect is to your computer. So change this, we’re going to adjust the throttle to Fast 3G speed in our Developer Tools:

React File Uploader — Adjusting Connection Speed

Now when we drop our file, we should see the following percentages.

React File Uploader — Progressive Upload

And there you have it. You have a drag and drop progress file uploader. The next few steps are more aesthetic cleanup and better state handling, but if you got value from this please skip to step Going From Here, otherwise continue with Step 7 — Cleaning Up.

Step 7 — Cleaning Up

The next steps are purely aesthetics and better handling so that we don’t bombard our browser with multiple files at once.

Prevent Further Drag & Drop While Uploading

For this we’re going to create a new state called enableDragDrop which we’ll wrap around our different event handlers. This will prevent the user from dropping another file midway to start another upload and wait until the first file is finished uploading.

File: /react-uploader/src/App.js

...
const App = () => {
const [status, setStatus] = useState('Drop Here');
const [percentage, setPercentage] = useState(0);
const [preview, setPreview] = useState(null);
const [enableDragDrop, setEnableDragDrop] = useState(true);
...const onDragEnter = event => {
if (enableDragDrop) {
setStatus('File Detected');
}
event.stopPropagation();
event.preventDefault();
};
...
const onDragLeave = event => {
if (enableDragDrop) {
setStatus('Drop Here');
}
event.preventDefault();
};
...
const onDragOver = event => {
if (enableDragDrop) {
setStatus('Drop');
}
event.preventDefault();
};
...
const onDrop = event => {
const supportedFilesTypes = ['image/jpeg', 'image/png'];
const { type } = event.dataTransfer.files[0];
if (supportedFilesTypes.indexOf(type) > -1 && enableDragDrop) {
...
// XHR - Upload Progress
xhr.upload.onprogress = (e) => {
const done = e.position || e.loaded
const total = e.totalSize || e.total;
const perc = (Math.floor(done/total*1000)/10);
if (perc >= 100) {
setStatus('Done');
setEnableDragDrop(true);
} else {
setStatus(`${perc}%`);
}
setPercentage(perc);
};
...
// XHR - Make Request
xhr.open('POST', 'http://localhost:5000/upload');
xhr.send(payload);
setEnableDragDrop(false);
}
event.preventDefault();
};

Reset When Done Uploading

File: /react-uploader/src/App.js

...
// XHR - Upload Progress
xhr.upload.onprogress = (e) => {
const done = e.position || e.loaded
const total = e.totalSize || e.total;
const perc = (Math.floor(done/total*1000)/10);
if (perc >= 100) {
setStatus('Done');
// Delayed reset
setTimeout(() => {
setPreview(null);
setStatus('Drop Here');
setPercentage(0);
setEnableDragDrop(true);
}, 750); // To match the transition 500 / 250

} else {
setStatus(`${perc}%`);
}
setPercentage(perc);
};
...

Modify Status For Better Visibility

I want to make sure our percentage and our status, while uploading is more visible.

File: /react-uploader/src/App.js

...<div className={`Status ${status.indexOf('%') > -1 || status === 'Done' ? 'Uploading' : ''}`}>{status}</div>...

File: /react-uploader/src/index.css

....Status {
background: transparent;
display: block;
font-family: 'Helvetica', Arial, sans-serif;
color: black;
font-size: 60px;
font-weight: bold;
text-align: center;
line-height: calc(80vh - 80px);
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
transition: all 250ms ease-in-out 0s;
}
.Status.Uploading {
background: rgba(0, 0, 0, 0.3);
color: white;
}
...
React File Uploader — Better Status Visibilty

Hiding Our White Borders

Last thing I want to do is hide our white borders when the upload process has happened.

File: /react-uploader/src/App.js

...<div className={`DropArea ${status === 'Drop' ? 'Over' : ''} ${status.indexOf('%') > -1 || status === 'Done' ? 'Uploading' : ''}`} onDragOver={onDragOver} onDragLeave={onDragEnter} onDrop={onDrop}>
<div className={`ImageProgress ${preview ? 'Show' : ''}`}>
...

File: /react-uploader/src/index.css

....DropArea.Over {
border: solid 40px rgba(0, 0, 0, 0.2);
}
.DropArea.Uploading {
border-width: 0px;
}
...
React File Uploader — No Borders

Adding Upload Abort Button

One thing I want to make sure we have is a way to abort the upload process all-together and make sure we give user’s more options / actions when uploading files.

File: /react-uploader/src/App.js

...const [enableDragDrop, setEnableDragDrop] = useState(true);
const [stateXhr, setStateXhr] = useState(null);
... // XHR - Make Request
xhr.open('POST', 'http://localhost:5000/upload');
xhr.send(payload);
setStateXhr(xhr);
setEnableDragDrop(false);
}
...
const onAbortClick = () => {
stateXhr.abort();
setPreview(null);
setStatus('Drop Here');
setPercentage(0);
setEnableDragDrop(true);
};
...
<div className={`Status ${status.indexOf('%') > -1 || status === 'Done' ? 'Uploading' : ''}`}>{status}</div>

{status.indexOf('%') > -1 && <div className="Abort" onClick={onAbortClick}><span>&times;</span></div>}
</div>
</div>
);
};
export default App;

File: /react-uploader/src/index.css

....Abort {
background: rgba(255, 0, 0, 0.5);
display: block;
position: absolute;
top: 0;
right: 0;
width: 50px;
height: 50px;
clip-path: polygon(0 0, 100% 100%, 100% 0);
transition: all 250ms ease-in-out 0s;
cursor: pointer;
}
.Abort:hover {
background: rgba(255, 0, 0, 1);
}
.Abort > span {
color: white;
font-family: 'Helvetica', Arial, sans-serif;
font-weight: bold;
font-size: 24px;
height: 28px;
width: 22px;
line-height: 28px;
position: absolute;
top: 0;
right: 0;
}

Now we can abort and reset our upload at anytime while a current file is uploading.

React File Upload — Abort Upload Button

Going From Here

There are a few other things we do to improve things:

  • Limit the file preview — that way it catches files that are too big to prevent them from bogging down the browser’s memory.
  • Handle other data like xls and pdf — CSV files can be read natively, and PDF files can previewed in a specific way with certain browsers.

This was quite a long walkthrough, so congrats on reading this far.

If you got value from, please give this article praise 👏❤️.️

If you think this can be improved, please let me know in the comments.

Please share it on twitter 🐦 or other social media platforms. Thanks again for reading. 🙏

Please also follow me on twitter: @codingwithmanny and instagram at @codingwithmanny.

--

--

Manny

DevRel Engineer @ Berachain | Prev Polygon | Ankr & Web Application / Full Stack Developer