3

I am currently designing a form using HTML, CSS, and JavaScript which includes an input type=file. I customized the form, so that the input now uses an image which can be clicked to browse and select files from the user's machine. However, I'd also like it to have drag & drop capabilities.

Below is the code I currently have. This code is enough to do a couple of things:

  1. It replaces the default 'Choose File' button that is rendered when using the input tag with type=file with the image called in the img tag.
  2. It uses some JavaScript for the span tag to indicate to the user which file they have selected or if no file has been selected.

The reason those are possible is because of the CSS used to change the default behavior in the input tag where type=file. However, I haven't found code to implement drag & drop to my current solution. Can somebody please help?

<style>
    .required-file::after {
    content: "*";
    color: red;
    }
    .custom-upload {
    display: inline-block;
    padding: 6px 12px;
    cursor: pointer;
    }
    input[type="file"] {
    display: none;
    }
    </style>
    <script>
    $(function() {
    const fileUploadElement = document.getElementById('fileUpload');
    const chosenFileElement = document.getElementById('chosen-file');
    fileUploadElement.addEventListener('change', function(){
    chosenFileElement.textContent = this.files[0].name;
    });
    });
    </script>
    <label for="fileUpload" class="custom-upload">
    <img src="/fakepath/image.png" width="100" height="100">
    </label>
    <input type="file" id="fileUpload" name="fileUpload" >
    <span class="required-file" id="chosen-file">No file chosen</span>
2
  • Something like this?
    – Ghost
    Commented Apr 25 at 20:43
  • 1
    Thanks, @Ghost! Could you please post this as an answer? This was exactly the kind of solution I was looking for. I would mark this as the accepted answer if I could.
    – aldodagio
    Commented Apr 25 at 23:10

3 Answers 3

0

Here's the solution

document.addEventListener("DOMContentLoaded", function() {
  const fileUploadElement = document.getElementById('fileUpload');
  const chosenFileElement = document.getElementById('chosen-file');
  const fileDropArea = document.getElementById('fileDropArea');

  const handleFileSelect = function(event) {
    event.stopPropagation();
    event.preventDefault();
    const files = event.dataTransfer.files;
    showFileName(files);
  };

  const handleDragOver = function(event) {
    event.stopPropagation();
    event.preventDefault();
    event.dataTransfer.dropEffect = 'copy'; 
  };

  const showFileName = function(files) {
    if (files.length > 0) {
      chosenFileElement.textContent = files[0].name;
    } else {
      chosenFileElement.textContent = 'No file chosen';
    }
  };

  fileDropArea.addEventListener('dragover', handleDragOver, false);
  fileDropArea.addEventListener('drop', handleFileSelect, false);

  fileUploadElement.addEventListener('change', function() {
    showFileName(this.files);
  });
});
.required-file::after {
  content: "*";
  color: red;
}

.custom-upload {
  display: inline-block;
  padding: 6px 12px;
  cursor: pointer;
  border: 2px dashed #ccc;
}

input[type="file"] {
  display: none;
}
<label for="fileUpload" class="custom-upload" id="fileDropArea">
        <img src="https://cataas.com/cat" width="100" height="100">
    </label>
<input type="file" id="fileUpload" name="fileUpload">
<span class="required-file" id="chosen-file">No file chosen</span>

0

Based on your requirements to add drag-and-drop capabilities and display the selected image, I've modified your code to include these features. Below is the updated HTML, CSS, and JavaScript that supports both functionalities seamlessly. This setup allows users to either click on the custom upload area to select a file or drag and drop a file onto it, and then immediately preview the selected image.

$(function () {
            const fileUploadElement = document.getElementById('fileUpload');
            const chosenFileElement = document.getElementById('chosen-file');
            const customUploadLabel = document.querySelector('.custom-upload');
            const imagePreview = document.getElementById('imagePreview');

            fileUploadElement.addEventListener('change', function () {
                displayImage(this.files[0]);
            });

            // Prevent default drag behaviors
            ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
                customUploadLabel.addEventListener(eventName, preventDefaults, false);
                document.body.addEventListener(eventName, preventDefaults, false);
            });

            // Highlight drop area when item is dragged over it
            ['dragenter', 'dragover'].forEach(eventName => {
                customUploadLabel.addEventListener(eventName, highlight, false);
            });

            ['dragleave', 'drop'].forEach(eventName => {
                customUploadLabel.addEventListener(eventName, unhighlight, false);
            });

            // Handle dropped files
            customUploadLabel.addEventListener('drop', handleDrop, false);

            function preventDefaults(e) {
                e.preventDefault();
                e.stopPropagation();
            }

            function highlight(e) {
                customUploadLabel.style.borderColor = '#666'; // Change as necessary
            }

            function unhighlight(e) {
                customUploadLabel.style.borderColor = '#ccc';
            }

            function handleDrop(e) {
                var dt = e.dataTransfer;
                var files = dt.files;

                if (files.length) {
                    fileUploadElement.files = files;
                    displayImage(files[0]);
                }
            }

            function displayImage(file) {
                if (file && file.type.startsWith('image/')) {
                    var reader = new FileReader();
                    reader.onload = function (e) {
                        imagePreview.src = e.target.result;
                        imagePreview.style.display = 'block';
                        chosenFileElement.textContent = file.name;
                    };
                    reader.readAsDataURL(file);
                } else {
                    chosenFileElement.textContent = 'No file chosen';
                    imagePreview.style.display = 'none';
                }
            }
        });
.required-file::after {
            content: "*";
            color: red;
        }

        .custom-upload {
            display: inline-block;
            padding: 6px 12px;
            cursor: pointer;
            border: 2px dashed #ccc;
        }

        input[type="file"] {
            display: none;
        }

        #imagePreview {
            width: 100px;
            height: 100px;
            min-height: 100px;
            min-width: 100px;
        }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<label for="fileUpload" class="custom-upload">
    <img id="imagePreview" src="/fakepath/image.png" alt="Preview">
</label>
<input type="file" id="fileUpload" name="fileUpload">
<span class="required-file" id="chosen-file">No file chosen</span>

0

what you are trying to do can easily be achieved with the javascript plugin called Dropzone and you can read more about the available configuration for the plugin dropzone configuration.

Below is an example:

<!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">
    <link rel="stylesheet" href="https://unpkg.com/dropzone@5/dist/min/dropzone.min.css" type="text/css">
    <title>Document Upload</title>
</head>

<body>
    <form action="/target" class="dropzone" id="my-great-dropzone"></form>

    <script src="https://unpkg.com/dropzone@5/dist/min/dropzone.min.js"></script>

    <script>
        Dropzone.options.myGreatDropzone = {
            // Camelized version of the `id`
            paramName: "file", // The name that will be used to transfer the file
            maxFilesize: 2, // MB
            uploadMultiple: false,
            addRemoveLinks: true
        };
    </script>
</body>

</html>

Not the answer you're looking for? Browse other questions tagged or ask your own question.