Featured image of post Implement Image File Upload and Preview using jQuery

Implement Image File Upload and Preview using jQuery

Learn how to create a clean image upload feature with live preview using jQuery. Improve UX with step-by-step code, tips, and real-time feedback for users.

Ever tried uploading a profile picture only to realize afterward that it wasn’t quite right? You’re not alone. According to UX research by NNGroup, nearly 1 in 5 user frustrations comes from confusing or limited upload experiences. That’s a big deal—especially considering how common file uploads are on the web.

Imagine running an online shop or setting up a profile page. Wouldn’t it be helpful if users could preview their images before submitting? A live image preview gives users instant feedback, builds confidence, and creates a smoother experience.

In this tutorial, we’ll walk through how to implement a clean, interactive image upload feature with live preview using jQuery. It’s beginner-friendly, reusable, and adds a polished touch to any website.


HTML: Building the Upload Interface

We’ll start by creating a simple HTML structure that handles image selection and preview.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<!-- Single image upload component -->
<div class="image_file">
    <label>
        <span class="upload"><img src="images/image_file_upload.png" alt="이미지 업로드"></span>
        <input type="file" class="file_input" accept="image/*">
    </label>
    <div class="preview">
        <span class="img_box"><img class="preview_img" src="#" alt="Selected Image"></span>
        <button type="button" class="delect"><img src="images/image_file_delect.png" alt="삭제"></button>
    </div>
</div>

What this does:

  • .image_file: Wraps everything into a neat upload module.
  • Clicking the label opens the file picker.
  • .upload shows an icon to encourage users to select a file.
  • .file_input: The hidden input that accepts image files only.
  • .preview: Displays the selected image and a delete button.

Want to allow multiple uploads? Just duplicate the entire .image_file block. Each one works on its own.


CSS: Styling the Upload Box and Preview

Next, we’ll use some simple CSS to style the upload area and make it intuitive to interact with.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
.image_file { position: relative; width: 200px; height: 200px; margin: 150px auto 0; } 
.image_file label { display: block; height: 100%; cursor: pointer; } 
.image_file .upload { display: flex; height: 100%; border: 1px dashed #E5E5E5; border-radius: 6px; justify-content: center; align-items: center; background: #FFFFFF; } 
.image_file .upload img { width: 40px; height: 40px; } 
.image_file .file_input { position: absolute; width: 1px; height: 1px; margin: -1px; font-size: initial; overflow: hidden; clip: rect(0, 0, 0, 0); } 
.image_file .preview { display: none; position: absolute; top: 0; left: 0; width: 100%; height: 100%; } 
.image_file .preview .img_box { display: block; height: 100%; border: 1px solid #E5E5E5; border-radius: 6px; background: #FFFFFF; cursor: pointer; } 
.image_file .preview .preview_img { width: 100%; height: 100%; object-fit: cover; } 
.image_file .preview .delect { position: absolute; top: 15px; right: 15px; width: 25px; height: 25px; padding: 0; border: none; background: none; cursor: pointer; } 
.image_file .preview .delect img { width: 100%; }  

Design tips:

  • Flexbox helps center the icon inside the box.
  • object-fit: cover makes sure the image fills the preview box neatly.

jQuery: Bringing the Preview to Life

Now for the fun part. With just a few lines of jQuery, we can show a preview as soon as the user selects an image, and allow them to remove it if needed.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
$(document).ready(function(){
    imageFileUpload();
});

// Initialize image upload and preview functionality
function imageFileUpload() {
    $('.image_file .delect').on('click', handleDeleteClick); // Handle delete button click
    $('.image_file .file_input').on('change', handleFileInputChange); // Handle file input change

    // When preview image is clicked, trigger file input click
    $('.image_file .preview_img').on('click', function() {
        $(this).closest('.image_file').find('.file_input').click();
    });

    // Handle file selection and update preview
    function handleFileInputChange() {
        const file = this.files[0];
        const previewContainer = $(this).closest('.image_file').find('.preview');
        const previewImage = previewContainer.find('.preview_img');

        if (file) {
            const reader = new FileReader();
            reader.onload = (e) => {
                previewImage.attr('src', e.target.result); // Set preview image
                previewContainer.show(); // Show preview box
                previewContainer.closest('.image_file').find('.upload').hide(); // Hide upload button
            };
            reader.readAsDataURL(file); // Read file as Data URL
        } else {
            resetPreview(previewContainer); // Reset if no file selected
        }

        // Update file count display (if in a modal with multiple file inputs)
        let file_cnt = 0;
        $('.file_select_pop .file_input').map(function(){
            if($(this).val()) file_cnt++;
        });
        $('.file_select_pop .file_cnt').html(file_cnt);
    }

    // Handle delete button click: reset preview and file input
    function handleDeleteClick() {
        const previewContainer = $(this).closest('.preview');
        resetPreview(previewContainer);

        // Update file count display
        let file_cnt = 0;
        $('.file_select_pop .file_input').map(function(){
            if($(this).val()) file_cnt++;
        });
        $('.file_select_pop .file_cnt').html(file_cnt);
    }

    // Reset the preview UI and clear the selected file
    function resetPreview(previewContainer) {
        const imageFileContainer = previewContainer.closest('.image_file');
        imageFileContainer.find('.file_input').val(''); // Clear file input
        previewContainer.hide(); // Hide preview box
        imageFileContainer.find('.upload').show(); // Show upload button again
    }
}  

How it works:

  • FileReader is a browser API that lets us read the file directly from the user’s device.
  • readAsDataURL() turns the file into a base64-encoded string we can use in the src attribute of an image tag.
  • We also add a handy trick: clicking the preview image will reopen the file picker so users can swap the image easily.

Final Thoughts

Adding a live preview to your image upload flow might seem like a small detail—but it makes a big impact. It reduces user mistakes, improves clarity, and makes your app feel polished and professional.


Want to take it to the next level?

  • Add drag-and-drop support.
  • Use Cropper.js to let users trim images before upload.
  • Add file size or dimension validation to prevent issues later.

Every small upgrade to your user interface builds trust and delight. Try this feature in your next project, and see how much smoother the experience feels. Got questions or want to show off what you built? Let us know in the comments!


Licensed under CC BY-NC-SA 4.0
comments powered by Disqus
Hugo로 만듦
JimmyStack 테마 사용 중