File Drop Zone

A drag-and-drop area for uploading files, with size and type validation.

Custom trigger

Choose a file using a dedicated trigger.

No image selected

Installation

npx lily-svelte@latest add file-drop-zone

Installs the style saved in lily.json. For a new Diamond project, run lily-svelte init --style diamond first.

Usage

<script lang="ts">
	import { FileDropZone } from '$lib/components/ui/file-drop-zone';
 
	let files = $state<string[]>([]);
</script>
 
<FileDropZone
	accept="image/*"
	maxFiles={5}
	fileCount={files.length}
	maxFileSize={5 * 1024 * 1024}
	onUpload={(uploaded) => (files = [...files, ...uploaded.map((f) => f.name)])}
	onFileRejected={({ file, reason }) => console.warn(reason, file.name)}
/>

Use compound mode when only a specific control should open the file picker. This keeps adjacent buttons, such as delete or retry actions, independent from file selection.

<script lang="ts">
	import * as FileDropZone from '$lib/components/ui/file-drop-zone';
	import { Button } from '$lib/components/ui/button';
</script>
 
<FileDropZone.Root clickToSelect={false} maxFiles={1} onUpload={handleUpload}>
	<div class="flex items-center gap-3">
		<span class="flex-1">Current file.png</span>
		<FileDropZone.Trigger>
			{#snippet child({ props })}<Button {...props} size="md">Change</Button>{/snippet}
		</FileDropZone.Trigger>
		<Button variant="ghost" size="md" onclick={deleteFile}>Delete</Button>
	</div>
</FileDropZone.Root>

Props

  • accept — comma-separated list, e.g. "image/*,.pdf".
  • maxFiles / fileCount — limit the total number of files (pass the current count).
  • maxFileSize — maximum bytes per file.
  • onUpload(files) — receives the accepted files.
  • onFileRejected({ file, reason }) — called per rejected file.
  • clickToSelect — when true (default), the whole root opens the picker; set it to false and use one or more FileDropZone.Trigger components for compound layouts.

FileDropZone.Trigger accepts a child snippet with button props for composing a Lily Button. The supplied disabled state and click handler preserve upload restrictions and keyboard activation.

Built by levish. The source code is available on GitHub.

Quiet by design.