DEV Community

Cover image for How to show Image Preview from Input element.
Kehinde Adeleke
Kehinde Adeleke

Posted on

How to show Image Preview from Input element.

Ever wanted to style the input with type="file" form control, and have a mini image preview in addition to that, you are in the right place.

Today, we will walk through how to make that specific input element accessible and beautiful.

Before that, a brief introduction:

Introduction: Forms Ubiquity

Forms are one of the key components of the web. They are everywhere. If you want to login or sign up for a service, you interact with a form. If you need to provide feedback for a product, your data is collected with a form.

It is therefore paramount that as users and designers of forms, we should work towards making sure, they aren't a hassle to fill in. They are easy to understand, and the user leaves with the reassurance that they have filled in the appropriate details.

If you need a deep dive into how to create accessible forms, web.dev by Google developers has a wonderful module on forms. You can access it by clicking here

For today, we are going to be working with the input element. Specifically, the input element of type="file". This input element is used to help users select and upload files from their devices. It could be mobile or desktop.

One issue with this input form control though is: it is very difficult to style. The default look of it when you create an input element is this:

<input type="file></input>
Enter fullscreen mode Exit fullscreen mode

Input type file

It is easy to understand. Yet, not exactly how we want it to be.

We want the label styles to look like a button and also show an image Preview. Let's get right on to it.

The whole project can be found on JSFiddle. If you are interested in seeing the final result, click the Link to JSFiddle playground

If you do want to code along from scratch, let's get started.

This project is going to be divided into three sections:

  1. The Markup
  2. The Styling
  3. Interactivity with JavaScript

The Markup

The Markup is the HTML we have to work with. The required elements we need are:

<div class="container">
  <label for="file" id="file-upload">Select an Image</label>
  <input type="file" name="file-upload" 
  id="file" accepts=".jpg, .jpeg, .png">

  <div class="preview">
    <img id="file-preview">
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

Let's look at what this markup is all about. We create a div with a class of Container. This div is going to contain both our form control -- the input of type="file" -- and the image element we need to display as a preview.

Next is the label for the input element. For accessibility, input fields should always have a label that describes the form control. Here the label has a for attribute of file which corresponds to the id of the input element.

Just think of it this way, the label for attribute tells us what form it is linked to. The form it is linked to will have the same value in its id.

so label for="file" tells screen readers that it is related to the input id="file". Remember that attributes values are case sensitive. file is not the same as File. that could potentially trip you up so be wary of it.

Next we have our form control with a name and an id. We add the accepts attribute that tells us what can be uploaded. Here it is delimited to files that have the .jpg, .jpeg or .png extension. That attribute is optional and you can safely take it out.

The next line of code is our container with the class of preview. This container will hold our image element inside of it. The image element doesn't have a src nor alt attribute...yet. It has an id. We are going to insert the src and alt attribute with the help of JavaScript.

Once you have all that done, you should have this:

basic input form control

We have our basic form control. Next, onto styling.

The Styling

CSS is always fun to write. We are going to be doing quite a lot to transform our meh input form control to an attractive button.
Let's get started:

First, we give our body element, a height of 100vh

body{
  height: 100vh;
}
Enter fullscreen mode Exit fullscreen mode

Next, we style our container.

.container {
  width: 100vh;
  height: 100vw;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
}
Enter fullscreen mode Exit fullscreen mode

We give the container, a height and width property. Next we add the display: flex property to align the children of the container to the center of it. The flex-direction changes the orientation of the children from row to column

With that, we should have this:
basic form control styling

The next step is to style the form control. Input fields of type file are not exactly easy to style so we are going to style the label element instead. Remember, the for attribute we added before. Now it is going to come in handy. Because we set a for attribute on the label element, we can visually hide the input element from the screen and yet still trigger the corresponding action. Let's see that in code

label {
  background: hotpink;
  padding: 15px 20px;
  border-radius: 5px;
  font-weight: bold;
  color: white;
  text-transform: uppercase;
  cursor: pointer;
  font-family: Avenir, Helvetica, Arial, sans-serif;
  font-size: 11px;
  box-shadow: 0 3px 10px 0 rgba(0,0,0,0.2), 0 6px 20px 0 rgba(0,0,0,0.19);
  transition: box-shadow ease 0.25s;
}

label:active {
  box-shadow:none;
}
Enter fullscreen mode Exit fullscreen mode

We have basic button styles. We give it a background of hotpink -- because hotpink is the best color -- padding, border-radius etc.

The box-shadow is to make our button have this push down effect. We would get to that soon. the active pseudo-class is added to the label element in order to remove the box-shadow when it is active.

Quick Info on the active pseudoclass by MDN:

The :active CSS pseudo-class represents an element (such as a button) that is being activated by the user. When using a mouse, "activation" typically starts when the user presses down the primary mouse button.

With all that added, we should have this:

button styled with input element

The input element is still present. We can style this by either using the opacity property or making it non-visible. The opacity property is recommended because, according to MDN:

Note: opacity is used to hide the file input instead of visibility: hidden or display: none, because assistive technology interprets the latter two styles to mean the file input isn't interactive.

We still want assistive technologies to know that we can interact with the form control. The way I did it was to just make the input element miniscule. Here's the code:

input#file {
  width: 0;
  height: 0;
}
Enter fullscreen mode Exit fullscreen mode

which gives us:
button

Here it is in motion:

button click animation

We have that nice click effect.

For the image element, we can hide it for now. You can do that by using the line of code below:

img{
  width: 50px;
  height: 50px;
  display: none;
}

.preview{
  margin-top: 20px;
  position: relative;
  left: -50px;
  width: 50px;
  height: 50px;
}
Enter fullscreen mode Exit fullscreen mode

That is all for our button styles and our image element.
We are going to style the container with the class of preview for a couple of reasons. First, we want a margin to separate our image from the button. We also wouldn't want any jarring layout shift so we set an extrinsic size with the width and height property.

The position property is to align it along the left margin of the button.

All that's left to add is JavaScript to display the image.

Interactivity with JavaScript.

The first thing to do is to get the input element from the DOM tree and assigning it to a variable. We do that by typing this:

const uploadButton = document.querySelector('input[type="file"]')
Enter fullscreen mode Exit fullscreen mode

Next, we add an EventListener to the input element, we listen for a change event because a change event signifies that a file has been added, followed by an arrow function with the event object.

uploadButton.addEventListener('change', (e)=>{
   const currFiles = e.target.files
})
Enter fullscreen mode Exit fullscreen mode

After that, we get the current files in the object

uploadButton.addEventListener('change', (e)=>{
   const currFiles = e.target.files
})

Enter fullscreen mode Exit fullscreen mode

We then check to see if the currFiles array is not empty, get the first file in the array, and append that to our image element. We use the getElementById method to get the image element with an id of file-preview.

After that, we add the image src to the src attribute of our image element and change the display of the image element from display:none to display:block.

uploadButton.addEventListener('change', (e)=>{
const currFiles = e.target.files
if(currFiles.length > 0){
      let src = URL.createObjectURL(currFiles[0])
      let imagePreview = document.getElementById('file-preview')
      imagePreview.src = src
      imagePreview.style.display = "block"
    }
})

Enter fullscreen mode Exit fullscreen mode

Your final JS code should look like this:

let uploadButton = document.querySelector('input[type="file"]')
uploadButton.addEventListener('change', (e)=>{
const currFiles = e.target.files
if(currFiles.length > 0){
      let src = URL.createObjectURL(currFiles[0])
      let imagePreview = document.getElementById('file-preview')
    imagePreview.src = src
      imagePreview.style.display = "block"
    }
})
Enter fullscreen mode Exit fullscreen mode

That is all for the code. The final output should look like this:

button-upload image preview

It's a small image but it does the work of letting the user know that they have selected an image.

Thanks for reading this.

One interesting thing you could try to implement is zoom on click. When the user clicks on the preview image, they are able to see the image pop up like a modal and with more clarity.

Recommended Resources:

  1. MDN article on input type file

  2. MDN article on createObjectURL

  3. MDN article on the DOM

Banner Image source: https://web.dev/learn/forms/fields/

Top comments (1)

Collapse
 
abhinavnaman profile image
Abhinav Naman

"Interactivity with JavaScript" was really helpful..thanks