enes

File Uploader AI

The File Uploader lets users pick files, drag and drop them, or import them from the camera, the microphone, the screen, a link and cloud drives. It is built on the upup engine: without somewhere to upload to, the files go with the form like a native file input. With it, the user uploads the files with the upload button, or each file is uploaded as it is added with autoUpload, and the form submits their keys.

Choose a file or drag and drop it here JPEG, PNG, PDF, and MP4 formats, up to 50 MB.

Usage

<script>
	import { FileUploader, Label } from 'fluentui-svelte';

	let files = $state([]);
</script>

<Label label="Upload" labelPosition="above">
	<FileUploader
		bind:files
		name="attachments"
		accept=".jpg,.jpeg,.png,.pdf,.mp4"
		maxFileSize={50 * 1024 * 1024}
		description="JPEG, PNG, PDF, and MP4 formats, up to 50 MB."
	/>
</Label>

Multiple Selection

Set multiple, or a maxFiles above 1, to accept several files, and maxFileSize, minFileSize or maxTotalFileSize to limit them. Files outside the limits are left out, with a message saying why. showLimits shows the limits at the foot of the drop zone.

Choose files or drag and drop them here 5 files max 10 MB each 30 MB in total

Sources

Each source in sources adds a button to the drop zone. Camera, audio and screen record in the browser, and a link imports a file from its URL. Cloud drives use googleDriveSource, oneDriveSource, dropboxSource and boxSource; only the ones passed are bundled.

Choose files or drag and drop them here
Demo only: the uploads are simulated in the browser, and some fail on purpose to show the retry.

The browser can only read a file from another site when that site allows it (CORS). To import from any link, send it through your server with fetchLink. Allow only the hosts you trust: a route that fetches any URL can reach your internal network.

<FileUploader
	sources={['local', 'url']}
	fetchLink={(url, signal) => fetch(`/api/fetch-link?url=${encodeURIComponent(url)}`, { signal })}
/>
// src/routes/api/fetch-link/+server.ts
import { error } from '@sveltejs/kit';

const ALLOWED_HOSTS = ['images.example.com', 'files.example.com'];

export async function GET({ url, fetch }) {
	const link = new URL(url.searchParams.get('url') ?? '');
	if (link.protocol !== 'https:' || !ALLOWED_HOSTS.includes(link.hostname)) error(400, 'Link not allowed');
	// A redirect could lead to a host out of the list: it fails instead.
	const response = await fetch(link, { redirect: 'error' }).catch(() => error(502, 'The file could not be fetched'));
	if (!response.ok) error(502, 'The file could not be fetched');
	return new Response(response.body, {
		headers: {
			'content-type': response.headers.get('content-type') ?? 'application/octet-stream',
			'content-disposition': response.headers.get('content-disposition') ?? ''
		}
	});
}

Uploading

Pass upload with an uploadEndpoint, or a serverUrl for @useupup/server. The files are uploaded with the button under the list, or as soon as they are added with autoUpload, and the form submits the key of each file instead of the file. A submission waits until every file is uploaded.

Choose files or drag and drop them here 10 files max 50 MB each
Demo only: the uploads are simulated in the browser, and some fail on purpose to show the retry.

The uploadEndpoint receives the name, size and type of each file, and returns its key and a presigned URL of your storage to upload it to.

// src/routes/api/upload-token/+server.ts
import { json } from '@sveltejs/kit';
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';

const s3 = new S3Client({ region: 'us-east-1' });

export async function POST({ request }) {
	const { name, type } = await request.json();
	const key = `uploads/${crypto.randomUUID()}-${name}`;
	const uploadUrl = await getSignedUrl(s3, new PutObjectCommand({ Bucket: 'my-bucket', Key: key, ContentType: type }), {
		expiresIn: 300
	});
	return json({ key, uploadUrl });
}

Forms

Without upload, the uploader is a native file input: the form submits the files under its name, and required, reset and the Label work as with any field. Submit the form with no file to see the invalid state.

Choose files or drag and drop them here 3 files max 5 MB each

Labels

labels changes any text of the uploader. Pass only the texts to change; the rest stay in English (FILE_UPLOADER_LABELS). Texts with a value, like tooLarge, are functions.

Drop your résumé here PDF or Word, up to 2 MB.

State and Events

Bind files to read the list: each file is a File with its status and, once uploaded, its key. onFilesAdded, onFileRemoved and onReject follow the list, and onUploadComplete and onUploadError the uploads. Bind uploader to drive the upup engine itself: upload(), pause(), resume() or cancel().

Choose files or drag and drop them here
0 files · 0.0 MB

Form Control Attributes

Attributes and events apply to the native form field; ref gives you access to it. For the container, use wrapperAttributes and wrapperRef.

Component Props

NameTypeDefaultDescription
files bindableFileUploaderFile[][]The files of the list. Read it, or bind it, to know what the user chose and what was uploaded. The files it starts with join the list.
sources(FileUploaderSource | FileUploaderDrive)[]['local']Where the files can come from. Each source other than local adds a button to the drop zone. Cloud drives use googleDriveSource, oneDriveSource, dropboxSource or boxSource; only the ones passed are bundled. Read once, on creation.
uploadFileUploaderUploadOptionsWhere and how the files are uploaded. With an uploadEndpoint or a serverUrl, the files are uploaded, and the form submits what uploadedValue returns for each one instead of the file. Without them, the form submits the files.
autoUploadbooleanfalseUploads each file as soon as it is added. Without it, a button uploads the waiting files, and the form cannot be submitted until they are uploaded.
fetchLink(url: string, signal: AbortSignal) => Promise<Response>(url, signal) => fetch(url, { signal })Fetches the file of the link source. A browser reads a file of another site only when that site allows it (CORS); point this at a route of your server that fetches the link instead.
uploadedValue(file: FileUploaderFile) => string(file) => file.keyWhat the form submits for an uploaded file.
acceptstringThe file types accepted, like the accept attribute: extensions, MIME types or wildcards such as image/*.
maxFilesnumberThe maximum number of files. Above 1, it accepts several files, as multiple does.
maxFileSizenumberThe maximum size of a file, in bytes.
minFileSizenumberThe minimum size of a file, in bytes.
maxTotalFileSizenumberThe maximum size of all the files together, in bytes.
descriptionstring | SnippetThe line under the title of the drop zone, usually the accepted types and sizes.
showLimitsbooleanShows the limits of the uploader at the foot of the drop zone: the number of files, the size of each one and the size of all of them, the ones that are set.
labelsPartial<FileUploaderLabels>The texts of the uploader. The ones left out fall back to English.
uploader bindableUpupCore | nullThe upup engine of the uploader, to pause, resume or cancel the uploads, or to listen to its events. The engine runs in the browser only: it is null on the server, and set once the uploader is mounted.
onFilesAdded(files: FileUploaderFile[]) => voidCalled with the files added to the list.
onFileRemoved(file: FileUploaderFile) => voidCalled with a file removed from the list.
onReject(rejections: FileUploaderRejection[]) => voidCalled with the files left out of the list, and why.
onUploadComplete(files: FileUploaderFile[]) => voidCalled with the files of the list once every upload has ended.
onUploadError(error: Error, file?: FileUploaderFile) => voidCalled when an upload fails.
ref bindableHTMLInputElement | nullThe DOM reference of the native file input that holds the files. The other attributes of the uploader are applied to it.
buttonRef bindableHTMLButtonElement | nullThe DOM reference of the button that opens the file picker.
buttonAttributesHTMLButtonAttributesThe attributes to spread on the button that opens the file picker.
wrapperRef bindableHTMLDivElement | nullThe DOM reference of the wrapper element.
wrapperAttributesHTMLAttributesThe attributes to spread on the wrapper element.
NativeFieldAttributes<FileInputAttributes>
Edit this Doc View as Markdown