npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

svelte-dropzone-runes

v1.0.3

Published

Svelte component for fileupload and file dropzone. Compatible with Svelte 5 Runes

Downloads

53

Readme

📦 svelte-dropzone-runes

A lightweight, flexible, and fully-typed file dropzone component for Svelte 5, built with performance and customization in mind. Easily handle drag-and-drop or manual file selection with support for validation, custom rendering, and accessibility.

✨ Features

✅ Svelte 5-compatible (uses $props() and $state)

📁 Drag & drop or click to select files

🔎 File validation:

Accepts specific types

Min/max file size

Supports single/multiple files

🎨 Full custom UI rendering

🧩 Integration-friendly via rich event callbacks

🚫 Automatically prevents document-level drops (optional)

📦 Installation

npm install svelte-dropzone-runes

🛠 Props

| Prop | Type | Default | Description | |-----------------------------|---------------------------------------------|-----------------|----------------------------------------------------------------------------------------------------------------------------------------| | accept | string[] | undefined | Accepted MIME types or file extensions (e.g., ['image/jpeg']). | | disabled | boolean | false | Disables all interactions with the dropzone. | | maxSize | number | Infinity | Maximum file size (in bytes). | | minSize | number | 0 | Minimum file size (in bytes). | | multiple | boolean | false | Allows multiple files to be selected at once. If set false only the first file will be accepted. | | maxFileCountPerUpload | number | Infinity | Maximum number of files that can be uploaded at once. Requires multiple to be true. | | preventDropOnDocument | boolean | true | Prevents default drag-and-drop behavior on the entire document. | | disableDropzoneClick | boolean | false | Disables the ability to open the file dialog by clicking on the dropzone. | | disableDropzoneKeydown | boolean | false | Disables the ability to open the file dialog by pressing keys. | | disableDropzoneDrag | boolean | false | Disables drag-and-drop functionality. | | name | string | '' | The name of the input, required when used inside a form. | | required | boolean | false | Marks the input as required. | | dropzoneElement | HTMLElement | undefined | A custom dropzone HTML element. You can bind dropzone events to any element by passing it here. | | inputElement | HTMLInputElement | undefined | Used to access input element used inside svelte-dropzone-runes. | | CustomDropzone | Snippet<[CustomDropzoneProps]> | undefined | Function that renders a custom dropzone element. Use with dropzoneElement to bind dropzone events to the custom element. | | children | Snippet<[]> | undefined | Custom inner content (overrides the default message). |

🎯 Events

| Event | Types | Payload | Description | |-----------------------------|-----------------------------------------------|--------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------| | onDragenter | DropzoneEventHandler<DataTransferItem> | {acceptedFiles,fileRejections,event} | Callback when a drag event enters the dropzone area. | | onDragover | DropzoneEventHandler<DataTransferItem> | {acceptedFiles,fileRejections,event} | Callback when a file is dragged over the dropzone. | | onDragleave | DropzoneEventHandler<DataTransferItem> | {acceptedFiles,fileRejections,event} | Callback when a file leaves the dropzone area. | | onDrop | DropzoneEventHandler<File> | {acceptedFiles,fileRejections,event} | Callback when files are dropped onto the dropzone. | | onFileDialogCancel | () => void | | Callback when the file dialog is canceled. |

🚀 Usage

Basic Example


<script lang="ts">
	import Dropzone, { type DropzoneEvent, type RejectedFile } from 'svelte-dropzone-runes';

	let files = $state({
		acceptedFiles: [] as File[],
		rejectedFiles: [] as RejectedFile<File>[]
	});

	function handleFilesSelect(e: DropzoneEvent<File>) {
		files = e;
	}
</script>

<Dropzone onDrop={handleFilesSelect} />

Custom UI

<script lang="ts">
	import type { CustomDropzoneProps, DropzoneEvent,RejectedFile } from 'svelte-dropzone-runes';
	import Dropzone from 'svelte-dropzone-runes';
	let dropzoneElement: HTMLElement | undefined = $state();
	let files = $state({
		acceptedFiles: [] as File[],
		rejectedFiles: [] as RejectedFile<File>[]
	});

	function handleFilesSelect(e: DropzoneEvent<File>) {
		files = e;
		isDraggingOver = false;
	}
</script>

{#snippet CustomDropzone(props: CustomDropzoneProps)}
	<div bind:this={dropzoneElement} {...props}>Custom Dropzone</div>
{/snippet}

<Dropzone {dropzoneElement} onDrop={handleFilesSelect} {CustomDropzone}></Dropzone>

Full Page

<script lang="ts">
	import { browser } from '$app/environment';
	import type { DropzoneEvent } from 'svelte-dropzone-runes';
	import Dropzone from 'svelte-dropzone-runes';
	let dropzoneElement: HTMLElement | undefined = $state(
		browser ? document.documentElement : undefined
	);
	let files = $state({
		acceptedFiles: [] as File[],
		rejectedFiles: [] as RejectedFile<File>[]
	});
	let isDraggingOver = $state(false);

	function handleFilesSelect(e: DropzoneEvent<File>) {
		files = e;
		isDraggingOver = false;
	}
</script>

{#if isDraggingOver}
	<div style="width: 100dvw;height:100dvh;position:fixed;left:0%;top:0%;background:white;display:flex;justify-content:center;align-items:center" >
		<div
			style="width:calc(100% - 100px);height:calc(100% - 100px);display:flex;justify-content:center;align-items:center;margin:50px;"
		>
			Drop Here
		</div>
	</div>
{/if}

<Dropzone
	onDragenter={(e) => {
		isDraggingOver = true;
	}}
	onDragleave={(e) => {
		isDraggingOver = false;
	}}
	{dropzoneElement}
	onDrop={handleFilesSelect}
></Dropzone>

Example

<script lang="ts">
	import type { CustomDropzoneProps, DropzoneEvent, RejectedFile } from 'svelte-dropzone-runes';
	import Dropzone from 'svelte-dropzone-runes';
	let dropzoneElement: HTMLElement | undefined = $state();
	let isDraggingOver = $state(false);

	let files = $state({
		acceptedFiles: [] as File[],
		rejectedFiles: [] as RejectedFile<File>[]
	});

	function handleFilesSelect(e: DropzoneEvent<File>) {
		const { acceptedFiles, rejectedFiles } = e;
		files.acceptedFiles = [...files.acceptedFiles, ...acceptedFiles];
		files.rejectedFiles = [...files.rejectedFiles, ...rejectedFiles];
		isDraggingOver = false;
	}
	$effect(() => {
		if (isDraggingOver) {
			dropzoneElement?.classList.add('hover');
		} else {
			dropzoneElement?.classList.remove('hover');
		}
	});
</script>

{#snippet CustomDropzone(props: CustomDropzoneProps)}
	<div bind:this={dropzoneElement} class="dropzone custom-dropzone" {...props}>Custom Dropzone</div>
{/snippet}

<Dropzone
	accept={["image/*"]}
	multiple
	onDragenter={(e) => {
		isDraggingOver = true;
	}}
	onDragleave={(e) => {
		isDraggingOver = false;
	}}
	{dropzoneElement}
	onDrop={handleFilesSelect}
	{CustomDropzone}
></Dropzone>

<style>
	.dropzone {
		flex: 1;
		display: flex;
		flex-direction: column;
		align-items: center;
		padding: 20px;
		border-width: 2px;
		border-radius: 2px;
		border-color: #eeeeee;
		border-style: dashed;
		background-color: #fafafa;
		color: #bdbdbd;
		outline: none;
		transition: border 0.24s ease-in-out;
	}

	.dropzone:hover {
		border-color: #2196f3;
	}

	.dropzone:focus {
		border-color: #2196f3;
	}

	.custom-dropzone {
		background-color: wheat;
		color: black;
		transition: all 0.3s;
	}

	.custom-dropzone:focus {
		padding: 40px;

	}

	.custom-dropzone:hover {
		padding: 40px;
	}

	.custom-dropzone.hover {
		padding: 40px;
	}
</style>

📚 Important Notes

The underlying logic is inspired by react-dropzone and svelte-file-dropzone but tailored for idiomatic Svelte 5 use.

If using Custom UI bind dropzoneElement to the drop target inside the CustomUI. If using form, set name and required on the dropzone to tie into form validation. If not using multiple drag items after the first one will be rejected. You can't validate file size during drag events because DataTransferItem doesn't expose file size.

📄 License

MIT © Truirer