This guide will teach you how to set up an image uploader and display a preview on the screen using plain HTML, CSS & JavaScript.
Project Setup
Create a directory on your computer (e.g. file-upload) and three files inside:
- index.html
- styles.css
- scripts.js
HTML Template
Starting with HTML, we'll create a base template and link it with two other files:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- Font awesome for fa icons -->
<script src="https://use.fontawesome.com/fe459689b4.js"></script>
<!-- Including styles.css file -->
<link rel="stylesheet" type="text/css" href="./styles.css" />
<title>File upload with preview</title>
</head>
<body>
<!-- Including scripts.js file -->
<script src="./scripts.js"></script>
</body>
</html>
I've also included a script for the Font Awesome icons that we'll use for UI/UX.
Setting up file uploader
Now we add the HTML code for file upload within the two <body></body>
tags:
<div class="profile-picture">
<h1 class="upload-icon">
<i class="fa fa-plus fa-2x" aria-hidden="true"></i>
</h1>
<input
class="file-uploader"
type="file"
onchange="upload()"
accept="image/*"
/>
</div>
- The
<div class="profile-picture">
is our main container that the user will interact with and it will serve as a display for the uploaded image. - The
<h1 class="upload-icon">
is a heading for the icon that will appear over the image.
Looks pretty terrible, but we'll get to it shortly.
Peeking into the input
- Input
type="file"
is what tells HTML to change this input from its default behavior (textbox) to a button that can upload a file from your machine. - The
onchange="upload()"
is anonchange
event on the element that will trigger when the file is selected and invoke the functionupload()
that we'll create in the JavaScript file. - The
accept="image/*"
tag tells the app to look exclusively for image-type files when browsing through the files on your machine. Other file types won't appear in the window.
Styling the uploader
The downside of the default HTML <input/>
element has limited styling options. To make the file upload button look like the one in the cover picture we'll mask the <input/>
with the <div class="profile-picture">
covering it.
The app user will interact with the upload input by clicking on the <div class="profile-picture">
. To do that we'll give our container a style of position: relative
, while the <h1>
tag and the <input/>
tag will have a style of position: absolute
.
Inside the styles.css
file, we'll style each element.
Profile-picture container styles
.profile-picture {
opacity: 0.75;
height: 250px;
width: 250px;
position: relative;
overflow: hidden;
/* default image */
background: url('https://qph.cf2.quoracdn.net/main-qimg-f32f85d21d59a5540948c3bfbce52e68');
background-position: center;
background-repeat: no-repeat;
background-size: cover;
box-shadow: 0 8px 6px -6px black;
}
File-uploader input styles
.file-uploader {
/* make it invisible */
opacity: 0;
/* make it take the full height and width of the parent container */
height: 100%;
width: 100%;
cursor: pointer;
/* make it absolute */
position: absolute;
top: 0%;
left: 0%;
}
Upload-icon heading styles
We'll position the Font Awesome icon in the middle of the container and make it invisible by default.
.upload-icon {
position: absolute;
top: 45%;
left: 50%;
transform: translate(-50%, -50%);
/* initial icon state */
opacity: 0;
transition: opacity 0.3s ease;
color: #ccc;
-webkit-text-stroke-width: 2px;
-webkit-text-stroke-color: #bbb;
}
The icon will appear only after the user hovers over the container:
/* toggle icon state */
.profile-picture:hover .upload-icon {
opacity: 1;
}
Looks way better! Now onto adding the functionality.
Scripting the upload
Inside the script.js
file, we'll create the upload()
function that will be triggered by the <input onchange="upload">
event. Inside we're going to pick up the image from the <input class="file-uploader"
element in the HTML:
function upload() {
const fileUploadInput = document.querySelector('.file-uploader');
We can also validate the input based on the selected file type, file size, etc.
const fileUploadInput = document.querySelector('.file-uploader');
// using index [0] to take the first file from the array
const image = fileUploadInput.files[0];
// check if the file selected is not an image file
if (!image.type.includes('image')) {
return alert('Only images are allowed!');
}
// check if size (in bytes) exceeds 10 MB
if (image.size > 10_000_000) {
return alert('Maximum upload size is 10MB!');
}
Lastly, we'll make use of the built-in FileReader
class to convert the file we've uploaded (that is in Blob format) to a base64-encoded data URL representing the image.
const fileReader = new FileReader();
fileReader.readAsDataURL(image);
When the fileReader
finishes processing the Blob image, it will trigger the onload
event on the instance. Inside we'll use the base-64 URL as a background image of our container:
const fileReader = new FileReader();
fileReader.readAsDataURL(image);
fileReader.onload = (fileReaderEvent) => {
const profilePicture = document.querySelector('.profile-picture');
profilePicture.style.backgroundImage = url(</span><span class="p">${</span><span class="nx">fileReaderEvent</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nx">result</span><span class="p">}</span><span class="s2">)
;
}
Demo
Photo by Helena Lopes from Pexels
The next logical step is to upload the Blog image to a cloud, like a Cloudinary or an AWS S3 bucket, which is out of the scope of this article.
You can find the full code on the Github.
For more awesome content, be sure to check out my other blog on Medium and follow me on Twitter.
Top comments (0)