Close Menu
Soshace Digital Blog

    Subscribe to Updates

    Get The Latest News, Updates, And Amazing Offers

    What's Hot
    Beginners

    Java Stream API

    JavaScript

    Build Real-world React Native App #1: Splash screen and App Icon

    LinkedIn

    Strategies for Identifying High-Quality LinkedIn Prospects by Niche

    Important Pages:
    • Home
    • About
    • Services
    • Contact Us
    • Privacy Policy
    • Terms & Conditions
    Facebook X (Twitter) Instagram LinkedIn YouTube
    Today's Picks:
    • Scaling Success: Monitoring Indexation of Programmatic SEO Content
    • Leveraging Influencers: Key Drivers in New Product Launches
    • How Privacy-First Marketing Will Transform the Industry Landscape
    • The Impact of Social Proof on Thought Leadership Marketing
    • Balancing Value-Driven Content and Promotional Messaging Strategies
    • Top Influencer Marketing Platforms to Explore in 2025
    • Emerging Trends in Marketing Automation and AI Tools for 2023
    • Strategies to Mitigate Duplicate Content in Programmatic SEO
    Sunday, September 28
    Facebook X (Twitter) Instagram LinkedIn YouTube
    Soshace Digital Blog
    • Home
    • About
    • Services
    • Contact Us
    • Privacy Policy
    • Terms & Conditions
    Services
    • SaaS & Tech

      Maximizing Efficiency: How SaaS Lowers IT Infrastructure Costs

      August 27, 2025

      Navigating Tomorrow: Innovations Shaping the Future of SaaS

      August 27, 2025

      Maximizing Impact: Strategies for SaaS & Technology Marketing

      August 27, 2025
    • AI & Automation

      Enhancing Customer Feedback Analysis Through AI Innovations

      August 27, 2025

      Navigating the Impact of AI on SEO and Search Rankings

      August 27, 2025

      5 Automation Hacks Every Home Service Business Needs to Know

      May 3, 2025
    • Finance & Fintech

      Critical Missteps in Finance Marketing: What to Avoid

      August 27, 2025

      Analyzing Future Fintech Marketing Trends: Insights Ahead

      August 27, 2025

      Navigating the Complex Landscape of Finance and Fintech Marketing

      August 27, 2025
    • Legal & Compliance

      Exploring Thought Leadership’s Impact on Legal Marketing

      August 27, 2025

      Maximizing LinkedIn: Strategies for Legal and Compliance Marketing

      August 27, 2025

      Why Transparency Matters in Legal Advertising Practices

      August 27, 2025
    • Medical Marketing

      Enhancing Online Reputation Management in Hospitals: A Guide

      August 27, 2025

      Analyzing Emerging Trends in Health and Medical Marketing

      August 27, 2025

      Exploring Innovative Content Ideas for Wellness Blogs and Clinics

      August 27, 2025
    • E-commerce & Retail

      Strategic Seasonal Campaign Concepts for Online and Retail Markets

      August 27, 2025

      Emerging Trends in E-commerce and Retail Marketing Strategies

      August 27, 2025

      Maximizing Revenue: The Advantages of Affiliate Marketing for E-Commerce

      August 27, 2025
    • Influencer & Community

      Leveraging Influencers: Key Drivers in New Product Launches

      August 27, 2025

      Top Influencer Marketing Platforms to Explore in 2025

      August 27, 2025

      Key Strategies for Successful Influencer Partnership Negotiations

      August 27, 2025
    • Content & Leadership

      The Impact of Social Proof on Thought Leadership Marketing

      August 27, 2025

      Balancing Value-Driven Content and Promotional Messaging Strategies

      August 27, 2025

      Analyzing Storytelling’s Impact on Content Marketing Effectiveness

      August 27, 2025
    • SEO & Analytics

      Scaling Success: Monitoring Indexation of Programmatic SEO Content

      August 27, 2025

      Strategies to Mitigate Duplicate Content in Programmatic SEO

      August 27, 2025

      Effective Data Visualization Techniques for SEO Reporting

      August 27, 2025
    • Marketing Trends

      How Privacy-First Marketing Will Transform the Industry Landscape

      August 27, 2025

      Emerging Trends in Marketing Automation and AI Tools for 2023

      August 27, 2025

      Maximizing ROI: Key Trends in Paid Social Advertising

      August 27, 2025
    Soshace Digital Blog
    Blog / JavaScript / The Ultimate Guide to Drag and Drop Image Uploading with Pure JavaScript
    JavaScript

    The Ultimate Guide to Drag and Drop Image Uploading with Pure JavaScript

    Supun KavindaBy Supun KavindaDecember 27, 2019Updated:May 26, 2024No Comments11 Mins Read
    Facebook Twitter Pinterest Telegram LinkedIn Tumblr Email Reddit
    The Ultimate Guide to Drag and Drop Image Uploading with Pure JavaScript
    JS Drag and Drop
    Share
    Facebook Twitter LinkedIn Pinterest Email Copy Link

    In this guide, I’ll be explaining how to upload images by dragging and dropping. This includes dragging images

    1. From OS to browser
    2. From browser to browser

    I’ll be using Pure Javascript (no frameworks or libraries), and the code will be compatible with all modern browsers including IE 9+. Also, I haven’t used ES6 which means you won’t need a compiler like Babel to run the code.

    Our Drag & Drop function will do 5 things.

    1. Listen for drag and drop
    2. Indicate when a file is hovering on the drop region
    3. Validate dropped images
    4. Preview images
    5. Upload images

    However, relying completely on drag & drop is a bad idea because mobile users won’t like it. Also, most mobile browsers don’t even support the API. Here’s the browser support for Drag & Drop API from caniuse.com.

    the browser support for Drag & Drop API
    the browser support for Drag & Drop API

    Therefore, we will also allow users to simply upload files by selecting them (Via <input type="file").

    Here’s the final result of this tutorial:

    A demo is available on JSFiddle

    Let’s start with basic HTML.

    <div id="drop-region">
        <div class="drop-message">
            Drag & Drop images or click to upload
        </div>
        <div id="image-preview"></div>
    </div>
    

    Then, save the elements in Javascript variables.

    var // where files are dropped + file selector is opened
        dropRegion = document.getElementById("drop-region"),
        // where images are previewed
        imagePreviewRegion = document.getElementById("image-preview");
    

    File Selector

    For file selecting, we have to use <input type="file"> here. However, those default file selectors look old-fashioned and hard to style with CSS. Therefore, using fake file input, we can make dropRegoin opening the file selector when clicked.

    // open file selector when clicked on the drop region
    var fakeInput = document.createElement("input");
    fakeInput.type = "file";
    fakeInput.accept = "image/*";
    fakeInput.multiple = true;
    dropRegion.addEventListener('click', function() {
        fakeInput.click();
    });
    

    Note that the accept attribute (fakeInput.accept = "image/*") is used to limit the files to image files. You can also specify the mime type too. For example, if you only need users to select only GIF files, you can use image/gif. Or, multiple values like image/png, image/jpeg. The multiple attribute allows users to select multiple images at once.

    Now, when the dropRegion is clicked, the fakeInput will be clicked. So, the browser will open the OS file selector.

    Let’s add the onChange event to the file input.

    fakeInput.addEventListener("change", function() {
        var files = fakeInput.files;
        handleFiles(file);
    });
    

    fakeInput.files is a FileList which we can use to preview and upload images. We will create the handleFiles() function later.

    Drag Events

    The Drag & Drop API defines 8 events: 4 events for the draggable element and 4 events for the droppable element. We will only need the latter 4 when developing a drag & drop image uploading.

    • dragenter: a dragged item enters a valid drop target.
    • dragleave: a dragged item leaves a valid drop target.
    • dragover: a dragged item is being dragged over a valid drop target. Triggered every few hundred milliseconds.
    • drop: an item is dropped on a valid drop target.

    Adding Drag & Drop Functionality

    When a file is dragged into the browser from the OS, the browser will try to open and display it by default. We have to prevent default behaviors and stop propagating to upper elements for all the events. This ensures any external event (especially an event of an outer element) doesn’t crash the functionality.

    function preventDefault(e) {
        e.preventDefault();
          e.stopPropagation();
    }
    
    dropRegion.addEventListener('dragenter', preventDefault, false);
    dropRegion.addEventListener('dragleave', preventDefault, false);
    dropRegion.addEventListener('dragover', preventDefault, false);
    dropRegion.addEventListener('drop', preventDefault, false);
    

    Then, we can handle the drop event.

    function handleDrop(e) {
        var data = e.dataTransfer,
            files = data.files;
    
        handleFiles(files)      
    }
    
    dropRegion.addEventListener('drop', handleDrop, false);
    

    e.dataTransfer is a Data Transfer object which contains the dragged data. e.dataTransfer.files contains the dragged local files as a FileList which is exactly same as the files variable in the change event handler of the file input.

    Now it’s the time to create the handleFiles() function which gets a File List and upload each item.

    function handleFiles(files) {
        for (var i = 0, len = files.length; i < len; i++) {
            if (validateImage(files[i]))
                previewAnduploadImage(files[i]);
        }
    }
    

    We can loop through the FileList (files here) using a simple for loop. If each file is a valid image, we will preview and upload it.

    Read More:  Getting started with Git Hooks using ghooks

    Wait! There’s a problem. This only works if the files are dragged from the local file system. What if an image is dragged from another webpage? We will need to optimize our drop handler for this (This is quite tricky).

    Here’s the upgraded handleDrop function.

    function handleDrop(e) {
        var dt = e.dataTransfer,
            files = dt.files;
    
        if (files.length) {
    
            handleFiles(files);
    
        } else {
    
            // check for img
            var html = dt.getData('text/html'),
                match = html && /bsrc="?([^"s]+)"?s*/.exec(html),
                url = match && match[1];
    
    
    
            if (url) {
                uploadImageFromURL(url);
                return;
            }
    
        }
    
    
        function uploadImageFromURL(url) {
            var img = new Image;
            var c = document.createElement("canvas");
            var ctx = c.getContext("2d");
    
            img.onload = function() {
                c.width = this.naturalWidth;     // update canvas size to match image
                c.height = this.naturalHeight;
                ctx.drawImage(this, 0, 0);       // draw in image
                c.toBlob(function(blob) {        // get content as PNG blob
    
                    // call our main function
                    handleFiles( [blob] );
    
                }, "image/png");
            };
            img.onerror = function() {
                alert("Error in uploading");
            }
            img.crossOrigin = "";              // if from different origin
            img.src = url;
        }
    
    }
    

    Here if files are not selected, we will check for browser images. When you drag an image on the browser to another place, the image is dragged as HTML. So, we can get the HTML and check for src="" attribute which is the image URL. Then, we can fetch the image with Image object and convert it to a canvas. Finally, the canvas can be converted to a blob, and we can use our handleFiles function as usual.

    However, there some limitations to this implementation. This would not work if the image is from a server that blocks cross-domain requests. To solve that, you can use a proxy image server to fetch images. And, also dragging from chrome to firefox can also show errors. Even with those limitations, dragging from one page to another is a cool feature.

    Validating Images

    function validateImage(image) {
        // check the type
        var validTypes = ['image/jpeg', 'image/png', 'image/gif'];
        if (validTypes.indexOf( image.type ) === -1) {
            alert("Invalid File Type");
            return false;
        }
    
        // check the size
        var maxSizeInBytes = 10e6; // 10MB
        if (image.size > maxSizeInBytes) {
            alert("File too large");
            return false;
        }
    
        return true;
    }
    

    This function validates two attributes.

    1. File type – In this example, I have allowed jpg, png, and gif files. However, you can add or remove any valid MIME type.

    2. File size – I have set the maximum size to 10MB. It is a good practice to limit the file size to prevent malicious oversized uploading.

    Validating on the client-side has one advantage. The user can know instantly whether their image is valid. If we completely rely on server-side validation, the user has to wait until the upload is finished and the server processes the response. This can be a burden for the server if the image files are very large.

    (Validating file size from the client-side inadequate. You must validate it again on the server-side.)

    Previewing and Uploading Images

    1. Previewing

    There are several ways to preview the image.

    1. Preview after uploading – Upload the image, get the image URL, and display it.
    2. Preview before uploading – We can preview the image before uploading. This is fast and efficient. There are two Javascript methods we can use.
      1. URL.createObjectURL()
      2. FileReader.readAsDataURL()

    For this example, I’ll choose 2.2: Preview the image before uploading using FileReader.readAsDataURL().

    Let’s start

    function previewAnduploadImage(image) {
    
        // container
        var imgView = document.createElement("div");
        imgView.className = "image-view";
        imagePreviewRegion.appendChild(imgView);
    
        // previewing image
        var img = document.createElement("img");
        imgView.appendChild(img);
    
        // progress overlay
        var overlay = document.createElement("div");
        overlay.className = "overlay";
        imgView.appendChild(overlay);
    
    
        // ...
    }
    

    We will read the image in the next step and display it on img element. The overlay will be used to add a faded look to each image until uploaded. We will reduce the width of the overlay when the image is uploading.

    Let’s read the image and preview.

    // read the image...
    var reader = new FileReader();
    reader.onload = function(e) {
        img.src = e.target.result;
    }
    reader.readAsDataURL(image);    
    

    Here we create a FileReader object and set up the onload event handler for it. Then, we read the image as a data URL. This is done asynchronously. After the reading is finished, the onload callback will be called. The src attribute of the img element will be set to e.target.result which is a base64 data URL.

    Read More:  16 Best Web Development & Web Design Blogs

    2. Uploading

    We can use FormData interface to create form data to send them to the server. Then, we can use AJAX with XMLHttpRequest to perform an asynchronous upload.

    Creating form data:

    // create FormData
    var formData = new FormData();
    formData.append('image', image);        
    

    AJAX request:

    var uploadLocation = 'UPLOAD_LOCATION';
    
    var ajax = new XMLHttpRequest();
    ajax.open("POST", uploadLocation, true);
    
    ajax.onreadystatechange = function(e) {
        if (ajax.readyState === 4) {
            if (ajax.status === 200) {
                // done!
            } else {
                // error!
            }
        }
    }
    
    ajax.upload.onprogress = function(e) {
    
        // change progress
        // (reduce the width of overlay)
        var perc = (e.loaded / e.total * 100) || 100,
            width = 100 - perc;
    
        overlay.style.width = width;
    }
    
    ajax.send(formData);
    

    Here uploadLocation should be set to the server URL of the upload handler. The onreadystatechange event handler is called when the state is changed. ajax.readyState is 4 when the request is completed. ajax.status is the status code sent by the server. Usually, servers set the status code to 200 when the request is successful. ajax.upload.onprogress event handler is called each time when the progress is updated. In this function, we calculate the percentage of the progress and reduce that from the overlay’s width.

    And, the || 100 part is a simple bug fix. Sometimes, (e.loaded / e.total * 100) can return NaN. In that case, the default value, 100, will be used.

    Here’s the complete function.

    function previewAnduploadImage(image) {
    
        // container
        var imgView = document.createElement("div");
        imgView.className = "image-view";
        imagePreviewRegion.appendChild(imgView);
    
        // previewing image
        var img = document.createElement("img");
        imgView.appendChild(img);
    
        // progress overlay
        var overlay = document.createElement("div");
        overlay.className = "overlay";
        imgView.appendChild(overlay);
    
    
        // read the image...
        var reader = new FileReader();
        reader.onload = function(e) {
            img.src = e.target.result;
        }
        reader.readAsDataURL(image);
    
        // create FormData
        var formData = new FormData();
        formData.append('image', image);
    
        // upload the image
        var uploadLocation = 'UPLOAD_LOCATION';
    
        var ajax = new XMLHttpRequest();
        ajax.open("POST", uploadLocation, true);
    
        ajax.onreadystatechange = function(e) {
            if (ajax.readyState === 4) {
                if (ajax.status === 200) {
                    // done!
                } else {
                    // error!
                }
            }
        }
    
        ajax.upload.onprogress = function(e) {
    
            // change progress
            // (reduce the width of overlay)
    
            var perc = (e.loaded / e.total * 100) || 100,
                width = 100 - perc;
    
            overlay.style.width = width;
        }
    
        ajax.send(formData);
    
    }
    

    Finally, here’s the CSS I created. You can change it as you like.

    #drop-region {
        background-color: #fff;
        border-radius:20px;
        box-shadow:0 0 35px rgba(0,0,0,0.05);
        width:400px;
        padding:60px 40px;
        text-align: center;
        cursor:pointer;
        transition:.3s;
    }
    #drop-region:hover {
        box-shadow:0 0 45px rgba(0,0,0,0.1);
    }
    
    #image-preview {
        margin-top:20px;
    }
    #image-preview .image-view {
        display: inline-block;
        position:relative;
        margin-right: 13px;
        margin-bottom: 13px;
    }
    #image-preview .image-view img {
        max-width: 100px;
        max-height: 100px;
    }
    #image-preview .overlay {
        position: absolute;
        width: 100%;
        height: 100%;
        top: 0;
        right: 0;
        z-index: 2;
        background: rgba(255,255,255,0.5);
    }
    

    Additional Improvements

    1. Detect drag & drop feature and change the message

    It is not useful to show the message “Drag & Drop images or click to upload” on browsers which don’t support the Drag and Drop API. So, we can detect the feature and change the message.

    Detect function is taken from Modernizr.

    function detectDragDrop() {
        var div = document.createElement('div');
        return ('draggable' in div) || ('ondragstart' in div && 'ondrop' in div)
    }
    
    // change the message
    var dragSupported = detectDragDrop();
    if (!dragSupported) {
        document.getElementsByClassName("drop-message")[0].innerHTML = 'Click to upload';
    }    
    

    2. Highlight on dragenter

    We can highlight the dropRegion when a file is dragging over using the drag events.

    dropRegion.addEventListener('dragenter', highlight, false);
    dropRegion.addEventListener('dragover', highlight, false);
    dropRegion.addEventListener('dragleave', unhighlight, false);
    dropRegion.addEventListener('drop', unhighlight, false);
    
    function highlight() {
        dropRegion.classList.add('highlighted');
    }
    function unhighlight() {
        dropRegion.classList.remove("highlighted");
    }
    

    Then, some CSS for .highlighted will make the dropRegion more interesting. For example,

    .highlighted {
        background-color:grey;
    }
    

    Conclusion

    In this article, I described how to upload a file using drag and drop. It is true that some effort is needed to create a drag and drop functionality. However, if you use a library like jquery the DOM manipulation would be much easier even the process is the same. If you need it, you can use ES6 and make syntax shorter. The fetch() API can also be instead of XMLHttpRequest. Finally, check out and play with the JSFiddle I created. I used the free service IMGBB for image uploading.

    JavaScript js programming webdev
    Share. Facebook Twitter Pinterest LinkedIn Tumblr Email
    Supun Kavinda

      Related Posts

      Mastering REST APIs: Essential Techniques for Programmers

      December 18, 2024

      Streamlining Resource Allocation for Enhanced Project Success

      December 18, 2024

      Crafting Interactive User Interfaces Using JavaScript Techniques

      December 17, 2024
      Leave A Reply Cancel Reply

      You must be logged in to post a comment.

      Stay In Touch
      • Facebook
      • Twitter
      • Pinterest
      • Instagram
      • YouTube
      • Vimeo
      Don't Miss
      B2B Leads December 6, 2024

      Effective Strategies for Generating B2B Leads via Podcasting

      Podcasting has emerged as a powerful tool for B2B lead generation. To maximize its potential, focus on niche topics that resonate with your target audience, promote episodes through social media, and engage listeners with actionable insights to drive conversions.

      Handling HEIC Images in Angular: A Comprehensive Tutorial

      April 20, 2023

      An Introduction to Pinia: The Alternative State Management Library for Vue.js Applications

      March 29, 2023

      D3.js and Angular/Vue.js Integration

      November 29, 2017

      Categories

      • AI & Automation
      • Angular
      • ASP.NET
      • AWS
      • B2B Leads
      • Beginners
      • Blogs
      • Business Growth
      • Case Studies
      • Comics
      • Consultation
      • Content & Leadership
      • CSS
      • Development
      • Django
      • E-commerce & Retail
      • Entrepreneurs
      • Entrepreneurship
      • Events
      • Express.js
      • Facebook Ads
      • Finance & Fintech
      • Flask
      • Flutter
      • Franchising
      • Funnel Strategy
      • Git
      • GraphQL
      • Home Services Marketing
      • Influencer & Community
      • Interview
      • Java
      • Java Spring
      • JavaScript
      • Job
      • Laravel
      • Lead Generation
      • Legal & Compliance
      • LinkedIn
      • Machine Learning
      • Marketing Trends
      • Medical Marketing
      • MSP Lead Generation
      • MSP Marketing
      • NestJS
      • Next.js
      • Node.js
      • Node.js Lessons
      • Paid Advertising
      • PHP
      • Podcasts
      • POS Tutorial
      • Programming
      • Programming
      • Python
      • React
      • React Lessons
      • React Native
      • React Native Lessons
      • Recruitment
      • Remote Job
      • SaaS & Tech
      • SEO & Analytics
      • Soshace
      • Startups
      • Swarm Intelligence
      • Tips
      • Trends
      • Vue
      • Wiki
      • WordPress
      Top Posts

      Testing Laravel Applications Like a Pro with PHPUnit

      Laravel December 4, 2020

      Strategies for Maintaining Agility in Your Startup’s Growth

      Startups December 7, 2024

      20. Уроки Node.js. Потоки данных в Node.JS, fs.ReadStream

      Programming October 19, 2016

      Node.js Lesson 7: Console Module

      Node.js October 9, 2020

      Subscribe to Updates

      Get The Latest News, Updates, And Amazing Offers

      About Us
      About Us

      Soshace Digital delivers comprehensive web design and development solutions tailored to your business objectives. Your website will be meticulously designed and developed by our team of seasoned professionals, who combine creative expertise with technical excellence to transform your vision into a high-impact, user-centric digital experience that elevates your brand and drives measurable results.

      7901 4th St N, Suite 28690
      Saint Petersburg, FL 33702-4305
      Phone: 1(877)SOSHACE

      Facebook X (Twitter) Instagram Pinterest YouTube LinkedIn
      Our Picks
      Programming

      How To Secure Python Web App Using Bandit

      LinkedIn

      Analyzing LinkedIn Recommendations: A Key to Lead Generation

      Express.js

      How to mock a Sequelize database

      Most Popular

      Best Background Check Services Assessments

      Consultation

      Overcoming the Challenges of B2B Lead Generation Today

      B2B Leads

      Mapping the World: Creating Beautiful Maps and Populating them with Data using D3.js 

      JavaScript
      © 2025 Soshace Digital.
      • Home
      • About
      • Services
      • Contact Us
      • Privacy Policy
      • Terms & Conditions

      Type above and press Enter to search. Press Esc to cancel.