As a web developer, you know file uploads are often required as a core feature of many web apps. They enable users to upload files, such as documents and image files. For example, cloud storage platforms have file uploaders, enabling users to upload pictures and documents to the cloud.
Job portals like Indeed also provide a file uploader to upload resumes and cover letters. Creating a high-performance, user-friendly file uploader can be quick and easy with JavaScript and HTML thanks to features like HTML’s <input type=”file”> element, JavaScript’s event handling, and APIs like FileReader and FormData.
In this HTML file upload example JavaScript tutorial, we’ll show you how to create a user-friendly uploader with HTML and JavaScript.
Key takeaways
- HTML <input type=”file”> element allows us to create file upload functionality that enables users to select and upload files.
- We can use the ‘multiple attribute’ to enable multiple file uploads.
- JavaScript’s event handling capabilities allow us to detect changes, such as when a user selects files.
- JavaScript also helps with client-side validations. We can validate file type and size for security purposes.
- With XMLHttpRequest, we can send files to the server asynchronously.
Understanding the basics
Here are the key terms you must understand before creating a file upload functionality:
- File upload
File upload means uploading files to a web server or cloud storage through a file uploader. This is commonly used for profile pictures, resumes, documents, and multimedia files in web apps.
- HTML
HTML or HyperText Markup Language is the standard language used to structure web pages. It essentially determines how web pages are displayed in a web browser. For file uploads, HTML provides elements like <input type=”file”>.
- JavaScript
JavaScript is the most used scripting language for creating interactive web pages. Almost all modern websites use JavaScript to enhance interactivity. With JavaScript’s event handling capabilities and APIs, we can efficiently handle events and validate files. JavaScript also allows us to display previews and send files to a server asynchronously.
HTML and JavaScript work together to create a high-performance, user-friendly file picker or uploader. HTML basically creates the upload interface. The <input type=”file”> element is used to allow users to select a file. The <form> element enables us to submit the file input to the server.
Javascript handles events. It listens for file selection events. It also validates file types and sizes before uploading. We can also add image previews using JavaScript. Moreover, with JavaScript, we can implement AJAX-based uploads using FormData and fetch() or XMLHttpRequest. It enables users to upload files without reloading.
Setting Up Your HTML Form
First, we’ll create an HTML form that will allow users to select and upload files. Here are the key points:
- We’ll use the <input type=”file”> element. This element with a file type attribute is what will allow users to select and upload files.
- The input element simply allows users to select files from their devices and upload them. To send them to the server, we need to make an HTTP request. For this purpose, we’ll use the <form> tag to define the form. We’ll set the action attribute to the server endpoint that will handle the file upload and use the POST method.
- To specify that the form will be used to upload files, we’ll define the enctype=”multipart/form-data” attribute.
- We’ll add the ‘multiple attribute’ to the file input element to enable users to select multiple files simultaneously.
- We’ll also include a submit button (<input type=”submit”>). This button will allow users to submit files after selecting them.
Here is the complete code (index.html):
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="files" multiple>
<input type="submit" value="Upload">
</form>
Incorporating JavaScript for File Handling
Next, we’ll use JavaScript to enhance the file upload functionality. JavaScript event handling capabilities allow us to define functions (event handlers) that respond to specific user interactions or browser events. It also helps with client-side validations before the form is submitted.
In our file uploader, we’ll attach an event listener to the file input element. It will detect changes, such as when a user selects files. This listener will then retrieve the selected files and provide immediate feedback by displaying file previews or names.
Here is an example code to access files selected by users (JavaScript code):
<script>
document.getElementById('fileInput').addEventListener('change', function(event) {
const files = event.target.files;
const preview = document.getElementById('preview');
const message = document.getElementById('message');
preview.innerHTML = '';
message.textContent = '';
if (files.length === 0) {
message.textContent = 'No files selected.';
message.className = 'message error';
return;
}
for (const file of files) {
const fileItem = document.createElement('p');
fileItem.textContent = file.name;
preview.appendChild(fileItem);
}
});
</script>
Validating File Input with JavaScript
JavaScript also helps with client-side validations. These validations allow us to ensure that the selected files meet certain criteria before they are uploaded. This enhances security and user experience.
For file type validation, we can check the MIME type of each selected file and see if it matches the allowed types, such as images or PDFs. To validate file size, we can set a maximum file size limit and verify that each selected file does not exceed this limit.
Here is an example code for these validations:
const allowedTypes = ['image/jpeg', 'image/png', 'application/pdf'];
const maxSize = 5 * 1024 * 1024; // 5 MB
Here is the complete code:
const maxSize = 5 * 1024 * 1024; // 5MB
const allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'application/pdf'];
Array.from(files).forEach(file => {
if (file.size > maxSize) {
message.textContent = `File size of ${file.name} exceeds 5MB.`;
message.className = 'message error';
return;
}
if (!allowedTypes.includes(file.type)) {
message.textContent = `Invalid file type for ${file.name}.`;
message.className = 'message error';
return;
}
// File is valid; proceed with preview or upload
});
The above code checks the file type and size of each selected file. It’ll display error messages if any file doesn’t meet the specified criteria.
Using XMLHttpRequest to Send Files
The XMLHttpRequest object allows us to send files to the server asynchronously. This provides a better user experience as it eliminates the need for full-page reloads.
To set up XMLHttpRequest for file uploads, we’ll first create a FormData object and append files. Next, we’ll specify the HTTP method and the server endpoint. We’ll also track upload progress to provide real-time feedback and define a callback function to handle the server’s response after the upload is complete
Here is an example code:
const formData = new FormData();
Array.from(files).forEach(file => {
formData.append('files', file);
}
const xhr = new XMLHttpRequest();
xhr.open('POST', '/upload', true);
xhr.upload.onprogress = function(event) {
if (event.lengthComputable) {
const percentComplete = (event.loaded / event.total) * 100;
message.textContent = `Upload progress: ${percentComplete.toFixed(2)}%`;
}
};
xhr.onload = function() {
if (xhr.status === 200) {
message.textContent = 'Files uploaded successfully!';
message.className = 'message success';
} else {
message.textContent = 'Upload failed.';
message.className = 'message error';
}
};
xhr.send(formData);
});
In the above code, the ‘xhr.upload.onprogress’ event allows to track upload progress. When the upload is complete, ‘xhr.onload’ is triggered. ‘xhr.send(formData)’ sends the formData containing the selected files to the server.
Complete code
Here is an example code of a file uploader that incorporates all the above sections. This code also includes submit event handler:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Multi-File Upload with Preview and Progress</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f4f4f9;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
}
.upload-container {
background-color: #fff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
text-align: center;
width: 90%;
max-width: 600px;
}
.upload-container h1 {
margin-bottom: 20px;
color: #333;
}
.file-input {
margin-bottom: 20px;
}
.file-input input {
display: none;
}
.file-input label {
background-color: #007bff;
color: #fff;
padding: 10px 20px;
border-radius: 5px;
cursor: pointer;
}
.file-input label:hover {
background-color: #0056b3;
}
.preview {
margin-bottom: 20px;
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.preview img {
max-width: 100px;
margin: 10px;
border-radius: 5px;
}
.progress-container {
width: 100%;
background-color: #ddd;
border-radius: 5px;
margin-bottom: 20px;
height: 20px;
}
.progress-bar {
height: 100%;
width: 0;
background-color: #4caf50;
border-radius: 5px;
transition: width 0.3s;
}
.message {
font-size: 16px;
margin-top: 10px;
}
.message.success {
color: green;
}
.message.error {
color: red;
}
</style>
</head>
<body>
<div class="upload-container">
<h1>Upload Files</h1>
<form id="uploadForm">
<div class="file-input">
<input type="file" id="fileInput" name="files" accept="image/*,application/pdf" multiple required>
<label for="fileInput">Choose Files</label>
</div>
<div class="preview" id="preview"></div>
<div class="progress-container">
<div class="progress-bar" id="progressBar"></div>
</div>
<button type="submit">Upload</button>
</form>
<div class="message" id="message"></div>
</div>
<script>
document.getElementById('fileInput').addEventListener('change', function(event) {
const files = event.target.files;
const preview = document.getElementById('preview');
const message = document.getElementById('message');
preview.innerHTML = '';
message.textContent = '';
if (files.length === 0) {
message.textContent = 'No files selected.';
message.className = 'message error';
return;
}
const maxSize = 5 * 1024 * 1024; // 5MB
const allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'application/pdf'];
Array.from(files).forEach(file => {
if (file.size > maxSize) {
message.textContent = `File size of ${file.name} exceeds 5MB.`;
message.className = 'message error';
return;
}
if (!allowedTypes.includes(file.type)) {
message.textContent = `Invalid file type for ${file.name}.`;
message.className = 'message error';
return;
}
if (file.type.startsWith('image/')) {
const reader = new FileReader();
reader.onload = function(e) {
const img = document.createElement('img');
img.src = e.target.result;
preview.appendChild(img);
};
reader.readAsDataURL(file);
} else if (file.type === 'application/pdf') {
const fileElement = document.createElement('div');
fileElement.textContent = `PDF: ${file.name}`;
preview.appendChild(fileElement);
}
});
});
document.getElementById('uploadForm').addEventListener('submit', function(event) {
event.preventDefault();
const fileInput = document.getElementById('fileInput');
const files = fileInput.files;
const message = document.getElementById('message');
const progressBar = document.getElementById('progressBar');
if (files.length === 0) {
message.textContent = 'No files selected.';
message.className = 'message error';
return;
}
const formData = new FormData();
Array.from(files).forEach(file => {
formData.append('files', file);
});
const xhr = new XMLHttpRequest();
xhr.open('POST', 'http://localhost:5500/upload', true);
xhr.upload.onprogress = function(event) {
if (event.lengthComputable) {
const percentComplete = (event.loaded / event.total) * 100;
progressBar.style.width = percentComplete + '%';
}
};
xhr.onload = function() {
if (xhr.status === 200) {
message.textContent = 'Files uploaded successfully!';
message.className = 'message success';
} else {
message.textContent = 'Error uploading files.';
message.className = 'message error';
}
};
xhr.onerror = function() {
message.textContent = 'Error uploading files.';
message.className = 'message error';
};
xhr.send(formData);
});
</script>
</body>
</html>
The above code will display the following screen:
When you click ‘Choose File’ button, it’ll allow you to select files from your local device:
When you click the ‘upload’ button, it’ll display the message “File uploaded successfully”
Enhancing User Experience
We can enhance the user experience by providing feedback during the upload process. For example, we can implement progress bars or indicators. They show real-time upload status and assure users that their upload is in progress. Displaying clear messages based on upload results also helps improve the user experience.
Here is an example code to show real-time upload status with progress bars and display success/error messages:
<input type="file" id="fileInput">
<progress id="progressBar" value="0" max="100"></progress>
<p id="message"></p>
<script>
document.getElementById('fileInput').addEventListener('change', function(event) {
const file = event.target.files[0];
if (!file) return;
const formData = new FormData();
formData.append('file', file);
const xhr = new XMLHttpRequest();
xhr.open('POST', '/upload', true);
xhr.upload.onprogress = function(event) {
if (event.lengthComputable) {
const percent = (event.loaded / event.total) * 100;
document.getElementById('progressBar').value = percent;
}
};
xhr.onload = function() {
const message = document.getElementById('message');
if (xhr.status === 200) {
message.textContent = 'Upload successful!';
} else {
message.textContent = 'Upload failed.';
}
};
xhr.send(formData);
});
</script>
You can also add drag and drop functionality to enhance the user experience.
Security Considerations
Implementing security features is crucial when creating file upload functionality to protect user-uploaded files and data. If your upload functionality is not secure, cyber attackers can upload executable files, such as .php, .exe.
They can exploit the server in several dangerous ways through these files. Moreover, if a user downloads a .exe file, it could infect their device with malware, ransomware, or spyware.
For secure file uploads, restrict file extensions. In other words, allow only specific file formats, such as web compatible image formats (.jpg, .png). Also, check file types, sizes, and content.
Moreover, using HTTPS to encrypt data transfer will prevent interception. Using secure storage locations is also crucial to protect uploaded files from data breaches.
Common Issues and Troubleshooting
Here are common problems developers might face while implementing HTML file uploads with JavaScript:
- Upload functionality not working
- Slow upload speeds
- User-uploaded files are too large
- CORS errors
Check the server response logs to identify the issues with the upload functionality and fix them accordingly. For slow upload speeds, compress the files before uploading them.
To handle large files efficiently, use chunked uploads. Also, implement retry mechanisms for network failures and ensure the backend handles multipart form data correctly.
Conclusion
HTML and JavaScript together allow us to create user-friendly file upload functionality. By using HTML’s <input type=”file”> element and JavaScript’s event handling and APIs like FormData, we can create a file uploader with features like file preview, validation, and asynchronous uploads. In this guide, we’ve provided a step-by-step tutorial for creating file upload functionality with HTML and JavaScript.
Sidra is an experienced technical writer with a solid understanding of web development, APIs, AI, IoT, and related technologies. She is always eager to learn new skills and technologies.
Read More →