Upload the image with a preview using HTML, CSS & JavaScript
Tags: images, html, css, javascript
Published: 2024-01-22 06:32:52

---
title: Upload the image with a preview using HTML, CSS & JavaScript
published: true
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rrh3rpwepojshrsyxj9d.png
tags: Images, HTML, CSS, JavaScript
---
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:

```html
<!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:

```html
    <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.

![HTML template preview](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jw5kr059nnhufqwzt9dz.png)
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 an `onchange` event on the element that will trigger when the file is selected and invoke the function `upload()` 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

```css
.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

```css
.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.

```css
.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:

```css
/* toggle icon state */
.profile-picture:hover .upload-icon {
  opacity: 1;
}
```

![Styled file upload](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gnyrbjjofrk15g4mjrtp.png)

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:

```js
function upload() {

  const fileUploadInput = document.querySelector('.file-uploader');
```

We can also validate the input based on the selected file type, file size, etc.

```js
  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.

```js
  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:

```js
  const fileReader = new FileReader();
  fileReader.readAsDataURL(image);

  fileReader.onload = (fileReaderEvent) => {
    const profilePicture = document.querySelector('.profile-picture');
    profilePicture.style.backgroundImage = `url(${fileReaderEvent.target.result})`;
  }
```
## Demo

![Final demo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hxeath9s0cp4wcizxqc9.png)

Photo by Helena Lopes from [Pexels](https://www.pexels.com/photo/black-and-white-dog-1938126/)

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](https://gist.github.com/MirzaLeka/db9386c400fd75edd99f6d5162728f7f). 
For more awesome content, be sure to check out my other blog on [Medium](https://mirzaleka.medium.com/) and follow me on [Twitter](https://twitter.com/mirzaleka).