1 GitHub star = 1 new component.

Star the repo
Formsuploadfile

Drag & Drop Upload

Large interactive file upload zone.

Live Preview

Drag files here or browse

Usage

Copy and paste this code into your React component:

tsx
import { DragDropUpload } from 'react-component-kit-ui/forms';

<DragDropUpload id="files" accept="image/*" multiple />

Manual Installation

If you are not using the npm package, create a new file and paste the following code: src/components/DragDropUpload.tsx + DragDropUpload.css:

DragDropUpload.tsx
'use client';

import { useEffect, useRef } from 'react';
import './DragDropUpload.css';

/**
 * DragDropUpload โ€” A prominent file upload zone with drag-and-drop support and visual feedback.
 * 
 * @param {string} label - Primary instruction text. Default is "Drag files here or browse".
 * @param {string} id - HTML ID for the file input.
 * @param {string} name - HTML name binding.
 * @param {string} accept - Allowed file types (e.g. "image/*").
 * @param {boolean} multiple - Enable multiple file selection.
 */
export interface DragDropUploadProps {
  label?: string;
  id: string;
  name?: string;
  accept?: string;
  multiple?: boolean;
}

export function DragDropUpload({ label = "Drag files here or browse", id, name, accept, multiple = false }: DragDropUploadProps) {

  // Ported from the Astro <script>: runs once after mount (DOM logic kept as in the Astro kit).
  const mounted = useRef(false);
  useEffect(() => {
    if (mounted.current) return;
    mounted.current = true;
    document.querySelectorAll('[data-upload-zone]').forEach(zone => {
        const input = zone.querySelector('[data-upload-input]') as HTMLInputElement;
    
        zone.addEventListener('click', () => input.click());
    
        zone.addEventListener('dragover', (e) => {
          e.preventDefault();
          zone.classList.add('upload-zone--dragging');
        });
    
        ['dragleave', 'drop'].forEach(evt => {
          zone.addEventListener(evt, () => zone.classList.remove('upload-zone--dragging'));
        });
    
        zone.addEventListener('drop', (e) => {
          e.preventDefault();
          if ((e as DragEvent).dataTransfer?.files) {
            input.files = (e as DragEvent).dataTransfer!.files;
            // Trigger change
            input.dispatchEvent(new Event('change'));
          }
        });
      });
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  return (
    <>
      <div className="upload-zone" data-upload-zone data-rk-e188c4="">
        <div className="upload-zone__icon" aria-hidden="true" data-rk-e188c4="">
          <svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" data-rk-e188c4="">
            <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" data-rk-e188c4="" />
            <polyline points="17 8 12 3 7 8" data-rk-e188c4="" />
            <line x1="12" y1="3" x2="12" y2="15" data-rk-e188c4="" />
          </svg>
        </div>
        <p className="upload-zone__text" data-rk-e188c4="">
          {label.split('browse').map((part, i) => (
            i === 0 ? <span data-rk-e188c4="">{part} <span className="upload-zone__link" data-rk-e188c4="">browse</span></span> : part
          ))}
        </p>
        <input type="file" id={id} name={name} accept={accept} multiple={multiple} hidden className="upload-zone__input" data-upload-input data-rk-e188c4="" />
      </div>
    </>
  );
}

export default DragDropUpload;
DragDropUpload.css
/* DragDropUpload โ€” ported from astro-component-kit (forms/DragDropUpload.astro) */

.upload-zone:where([data-rk-e188c4]) { 
  border: 2px dashed var(--c-border, rgba(255,255,255,0.1)); 
  border-radius: var(--r-xl, 20px); 
  padding: var(--sp-12, 3rem); 
  text-align: center; 
  background: var(--c-bg-elev, rgba(255,255,255,0.02)); 
  cursor: pointer; 
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); 
  color: var(--c-text-2, #94a3b8); 
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-4, 1rem);
}

.upload-zone:hover:where([data-rk-e188c4]), .upload-zone--dragging:where([data-rk-e188c4]) { 
  border-color: var(--c-primary, #6366f1); 
  background: rgba(99, 102, 241, 0.05); 
  color: var(--c-text-1, #fff); 
  transform: translateY(-2px);
}

.upload-zone__icon:where([data-rk-e188c4]) { color: var(--c-primary, #6366f1); transition: transform 0.3s; }
.upload-zone:hover:where([data-rk-e188c4]) .upload-zone__icon:where([data-rk-e188c4]) { transform: translateY(-5px); }

.upload-zone__text:where([data-rk-e188c4]) { font-size: 1rem; margin: 0; }
.upload-zone__link:where([data-rk-e188c4]) { color: var(--c-primary, #6366f1); font-weight: 700; text-decoration: underline; text-underline-offset: 4px; }

Quick Info

Category
Forms
Filename
DragDropUpload.tsx
Dependencies
None โ€” pure React + CSS
Tags
uploadfile