Tailwind CSS Drag and Drop File Upload UI

in this section we will create tailwind css drag and drop box ui.

Tailwind CSS Dropbox File upload UI.

<div class="max-w-xl">
    <label
        class="flex justify-center w-full h-32 px-4 transition bg-white border-2 border-gray-300 border-dashed rounded-md appearance-none cursor-pointer hover:border-gray-400 focus:outline-none">
        <span class="flex items-center space-x-2">
            <svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 text-gray-600" fill="none" viewBox="0 0 24 24"
                stroke="currentColor" stroke-width="2">
                <path stroke-linecap="round" stroke-linejoin="round"
                    d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" />
            </svg>
            <span class="font-medium text-gray-600">
                Drop files to Attach, or
                <span class="text-blue-600 underline">browse</span>
            </span>
        </span>
        <input type="file" name="file_upload" class="hidden">
    </label>
</div>
drag and drop file upload image

Build a user-friendly multiple image file upload with preview, drag-and-drop, and image removal features using Tailwind CSS and JavaScript.

<body class="bg-gray-100 h-screen flex items-center justify-center">

    <div class="lg:max-w-xl w-full mx-auto p-6 bg-white rounded-md shadow-md">
        <label id="drop-zone"
            class="flex flex-col items-center w-full h-40 p-6 border-2 border-gray-300 border-dashed rounded-md cursor-pointer hover:border-gray-400 transition">
            <svg xmlns="http://www.w3.org/2000/svg" class="w-12 h-12 text-gray-400 mb-2" fill="none" viewBox="0 0 24 24"
                stroke="currentColor" stroke-width="2">
                <path stroke-linecap="round" stroke-linejoin="round"
                    d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" />
            </svg>
            <span class="text-sm text-gray-600">
                Drop files here or
                <span class="text-blue-600 underline">browse</span>
            </span>
            <input type="file" name="file_upload" class="hidden" id="file-input" multiple>
        </label>
        <div id="preview-container" class="mt-4 grid grid-cols-2 gap-4"></div>
    </div>

    <script>
        document.addEventListener('DOMContentLoaded', function () {
            const dropZone = document.getElementById('drop-zone');
            const fileInput = document.getElementById('file-input');
            const previewContainer = document.getElementById('preview-container');

            dropZone.addEventListener('dragover', function (e) {
                e.preventDefault();
                dropZone.classList.add('border-gray-400');
            });

            dropZone.addEventListener('dragleave', function () {
                dropZone.classList.remove('border-gray-400');
            });

            dropZone.addEventListener('drop', function (e) {
                e.preventDefault();
                dropZone.classList.remove('border-gray-400');

                const files = e.dataTransfer.files;
                handleFiles(files);
            });

            fileInput.addEventListener('change', function () {
                const files = fileInput.files;
                handleFiles(files);
            });

            function handleFiles(files) {
                for (const file of files) {
                    const reader = new FileReader();

                    reader.onload = function (e) {
                        const previewItem = createPreviewItem(e.target.result);
                        previewContainer.appendChild(previewItem);
                    };

                    reader.readAsDataURL(file);
                }
            }

            function createPreviewItem(imageSrc) {
                const previewItem = document.createElement('div');
                previewItem.classList.add('relative', 'group');

                const removeButton = document.createElement('button');
                removeButton.innerHTML = '×';
                removeButton.classList.add('absolute', 'top-2', 'right-2', 'text-white', 'bg-red-500', 'border-none', 'rounded-md', 'px-2', 'py-1', 'opacity-0', 'group-hover:opacity-100', 'transition');

                const previewImage = document.createElement('img');
                previewImage.src = imageSrc;
                previewImage.classList.add('w-full', 'h-32', 'object-cover', 'rounded-md', 'mb-2');

                removeButton.addEventListener('click', function () {
                    previewContainer.removeChild(previewItem);
                });

                previewItem.appendChild(previewImage);
                previewItem.appendChild(removeButton);

                return previewItem;
            }
        });
    </script>

</body>
multiple image drag and drop file with preview image

Tailwind CSS with Alpine.js drag and drop file upload.

<div x-data="{ image: '', handleFiles($event) { const file = $event.target.files[0]; this.readFile(file); }, readFile(file) { if (file) { const reader = new FileReader(); reader.onload = (e) => { this.image = e.target.result; }; reader.readAsDataURL(file); } } }"
    class="p-10 max-w-xl">
    <div @click="$refs.fileInput.click()"
        class="cursor-pointer border-dashed border-4 border-gray-200 rounded-lg p-10 text-center" @dragover.prevent
        @dragleave.prevent @drop.prevent="handleFiles($event)">
        <p>Drag and drop your image here or click to select a file</p>
        <input type="file" class="hidden" x-ref="fileInput" @change="handleFiles($event)" />
    </div>

    <div class="mt-4">
        <img x-show="image" :src="image" class="max-w-xs mx-auto" />
    </div>
</div>