File Uploader AI
El File Uploader permite elegir archivos, arrastrarlos y soltarlos, o importarlos desde la cámara, el micrófono, la pantalla, un enlace y nubes de almacenamiento. Está construido sobre el motor de upup: sin un destino de subida, los archivos se envían con el formulario como en un input de archivo nativo. Con él, el usuario sube los archivos con el botón de subida, o cada archivo se sube al añadirse con autoUpload, y el formulario envía sus claves.
Uso
<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> Selección múltiple
Usa multiple, o un maxFiles mayor que 1, para aceptar varios archivos, y maxFileSize, minFileSize o maxTotalFileSize para limitarlos. Los archivos fuera de los límites se dejan fuera, con un mensaje que dice por qué. showLimits muestra los límites al pie de la zona de soltar.
Orígenes
Cada origen en sources añade un botón a la zona de soltar. Cámara, audio y pantalla graban en el navegador, y un enlace importa un archivo desde su URL. Las nubes usan googleDriveSource, oneDriveSource, dropboxSource y boxSource; solo se incluyen las que pasas.
El navegador solo puede leer un archivo de otro sitio si ese sitio lo permite (CORS). Para importar desde cualquier enlace, pásalo por tu servidor con fetchLink. Permite solo los hosts en los que confías: una ruta que trae cualquier URL puede llegar a tu red interna.
<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') ?? ''
}
});
} Subida
Pasa upload con un uploadEndpoint, o un serverUrl para @useupup/server. Los archivos se suben con el botón bajo la lista, o en cuanto se añaden con autoUpload, y el formulario envía la clave de cada archivo en lugar del archivo. Un envío espera a que todos los archivos estén subidos.
El uploadEndpoint recibe el nombre, el tamaño y el tipo de cada archivo, y devuelve su clave y una URL prefirmada de tu almacenamiento a la que subirlo.
// 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 });
} Formularios
Sin upload, el uploader es un input de archivo nativo: el formulario envía los archivos bajo su name, y required, el reset y el Label funcionan como en cualquier campo. Envía el formulario sin archivos para ver el estado inválido.
Textos
labels cambia cualquier texto del uploader. Pasa solo los textos a cambiar; el resto queda en inglés (FILE_UPLOADER_LABELS). Los textos con un valor, como tooLarge, son funciones.
Estado y eventos
Enlaza files para leer la lista: cada archivo es un File con su status y, una vez subido, su key. onFilesAdded, onFileRemoved y onReject siguen la lista, y onUploadComplete y onUploadError las subidas. Enlaza uploader para manejar el motor de upup directamente: upload(), pause(), resume() o cancel().
Propiedades del componente
| Name | Type | Default | Description |
|---|---|---|---|
files bindable | FileUploaderFile[] | [] | Los archivos de la lista. Léela, o enlázala, para saber qué eligió el usuario y qué se subió. Los archivos con los que empieza se suman a la lista. |
sources | (FileUploaderSource | FileUploaderDrive)[] | ['local'] | De dónde pueden venir los archivos. Cada origen distinto de local añade un botón a la zona de soltar. Las nubes usan googleDriveSource, oneDriveSource, dropboxSource o boxSource; solo se incluyen las que pasas. Se lee una vez, al crearse. |
upload | FileUploaderUploadOptions | Dónde y cómo se suben los archivos. Con un uploadEndpoint o un serverUrl, los archivos se suben, y el formulario envía lo que devuelve uploadedValue por cada uno en lugar del archivo. Sin ellos, el formulario envía los archivos. | |
autoUpload | boolean | false | Sube cada archivo en cuanto se añade. Sin ella, un botón sube los archivos en espera, y el formulario no se puede enviar hasta que estén subidos. |
fetchLink | (url: string, signal: AbortSignal) => Promise<Response> | (url, signal) => fetch(url, { signal }) | Trae el archivo del origen de enlace. Un navegador solo lee un archivo de otro sitio si ese sitio lo permite (CORS); apúntalo a una ruta de tu servidor que traiga el enlace. |
uploadedValue | (file: FileUploaderFile) => string | (file) => file.key | Lo que el formulario envía por un archivo subido. |
accept | string | Los tipos de archivo aceptados, como el atributo accept: extensiones, tipos MIME o comodines como image/*. | |
maxFiles | number | El número máximo de archivos. Por encima de 1, acepta varios archivos, como multiple. | |
maxFileSize | number | El tamaño máximo de un archivo, en bytes. | |
minFileSize | number | El tamaño mínimo de un archivo, en bytes. | |
maxTotalFileSize | number | El tamaño máximo de todos los archivos juntos, en bytes. | |
description | string | Snippet | La línea bajo el título de la zona de soltar, normalmente los tipos y tamaños aceptados. | |
showLimits | boolean | Muestra los límites del uploader al pie de la zona de soltar: el número de archivos, el tamaño de cada uno y el de todos juntos, los que estén definidos. | |
labels | Partial<FileUploaderLabels> | Los textos del uploader. Los que se omiten quedan en inglés. | |
uploader bindable | UpupCore | null | El motor de upup del uploader, para pausar, reanudar o cancelar las subidas, o escuchar sus eventos. El motor solo se ejecuta en el navegador: es null en el servidor, y se asigna cuando el uploader se monta. | |
onFilesAdded | (files: FileUploaderFile[]) => void | Se llama con los archivos añadidos a la lista. | |
onFileRemoved | (file: FileUploaderFile) => void | Se llama con un archivo quitado de la lista. | |
onReject | (rejections: FileUploaderRejection[]) => void | Se llama con los archivos que quedaron fuera de la lista, y el motivo. | |
onUploadComplete | (files: FileUploaderFile[]) => void | Se llama con los archivos de la lista cuando terminan todas las subidas. | |
onUploadError | (error: Error, file?: FileUploaderFile) => void | Se llama cuando falla una subida. | |
ref bindable | HTMLInputElement | null | La referencia DOM del input de archivo nativo que contiene los archivos. Los demás atributos del uploader se aplican a él. | |
buttonRef bindable | HTMLButtonElement | null | La referencia DOM del botón que abre el selector de archivos. | |
buttonAttributes | HTMLButtonAttributes | Los atributos que se aplican al botón que abre el selector de archivos. | |
wrapperRef bindable | HTMLDivElement | null | La referencia DOM del elemento contenedor. | |
wrapperAttributes | HTMLAttributes | Los atributos que se aplican al elemento contenedor. | |
NativeFieldAttributes<FileInputAttributes> |

