Product Craft Bible
Upload Patterns
Inicio Media y Archivos Upload Patterns
Media y Archivos

Upload Patterns

8 reglas WCAG 2.1.1 Keyboard · WCAG 2.5.7 Dragging Movements · NN/g "Drag-and-Drop" · USWDS File InputWCAG 1.4.1 Use of Color · WCAG 1.4.11 Non-text Contrast · USWDS File InputWCAG 3.3.1 Error Identification · WCAG 3.3.3 Error Suggestion · USWDS File Input · Uploadcare UXSmashing Magazine "Animated Progress Indicators" (2016) · Uploadcare UX · Eleken "File Upload UI"
92

Upload Patterns

8 reglas
791

Drag & drop siempre con botón de fallback visible

El arrastrar y soltar es una interacción de raton por defecto: ni el teclado, ni el lector de pantalla, ni el móvil pueden activarla. Por eso toda zona de carga debe incluir un <input type="file"> con label visible como mecanismo equivalente, no como mejora opcional. WCAG 2.1.1 (Keyboard) exige que la selección de archivos sea operable por teclado, y WCAG 2.5.7 (Dragging Movements) pide que toda función con arrastre se logre con un solo puntero sin arrastrar. Nunca implementes el drop como único camino de carga.

WCAG 2.1.1 Keyboard · WCAG 2.5.7 Dragging Movements · NN/g "Drag-and-Drop" · USWDS File Input
Preferir
Arrastra tus archivos aquí o Accesible por teclado, raton y móvil
Evitar
Arrastra tus archivos aquí Tab no puede activar nada · móvil no arrastra
792

La dropzone comunica sus cuatro estados, no solo con color

Una zona de carga sin feedback al arrastrar deja al usuario sin saber si el blanco esta activo. Debe distinguir cuatro estados (inactivo, drag-over, subiendo y resultado) mediante borde, icono y texto, no solo color: WCAG 1.4.1 (Use of Color) prohibe que el color sea el único medio, y 1.4.11 (Non-text Contrast) exige 3:1 en el borde y los iconos de estado. El patrón reconocido es un borde punteado neutro que se rellena con un fondo tintado al arrastrar; durante la subida, reemplaza el contenido con el progreso para evitar re-drops a media carga.

WCAG 1.4.1 Use of Color · WCAG 1.4.11 Non-text Contrast · USWDS File Input
Preferir
Arrastra aquí Inactivo
Suelta para subir Drag-over
Subiendo
3 archivos listos Exito
Evitar
Arrastra aquí Mismo aspecto siempre
793

Valida tipo, tamaño y cantidad en el cliente antes de subir

Subir un archivo de tipo prohibido o sobredimensionado para que falle en el servidor desperdicia tiempo y ancho de banda. La validación debe ocurrir justo después de seleccionar, antes de transferir bytes, con un mensaje específico por archivo. WCAG 3.3.1 (Error Identification) exige identificar en texto el elemento erroneo y 3.3.3 (Error Suggestion) sugerir la corrección. El atributo accept filtra el picker pero es saltable, así que refuerzalo con JS, y empareja el error con una region aria-live porque el error visual solo no se anuncia al lector.

WCAG 3.3.1 Error Identification · WCAG 3.3.3 Error Suggestion · USWDS File Input · Uploadcare UX
Preferir
resume_final.pdf
45 MB
Archivo demasiado grande (45 MB). El máximo es 10 MB.
Evitar
La carga fallo.
794

Muestra progreso por archivo y total, con acción de cancelar

El usuario necesita saber que su carga avanza, cuanto falta y mantener el control para abortarla. Una barra de progreso se vuelve necesaria para cargas que superen ~10 segundos; por debajo basta un spinner (Smashing Magazine, citando a Nielsen). Cada archivo de una cola multiple lleva su propio indicador, y un resumen muestra el total ("2 de 3 archivos · 78%"). Nunca congeles la barra al 99%: disimula la espera con movimiento constante. El botón de cancelar debe estar presente y no pedir confirmación mientras la carga no termina.

Smashing Magazine "Animated Progress Indicators" (2016) · Uploadcare UX · Eleken "File Upload UI"
Preferir
2 de 3 archivos
78%
portada.jpg
100%
video_demo.mp4
67%
manual.pdf
8%
Evitar
Subiendo...
795

Previsualiza lo seleccionado con acción de eliminar por item

Tras seleccionar archivos, el usuario necesita confirmar visualmente que escogio los correctos antes de subir. Muestra miniaturas para imagenes e iconos por tipo con nombre y tamaño para el resto; los thumbnails atrapan errores de archivo equivocado (subir "contract_v1.pdf" en vez de "contract_final.pdf") antes de gastar ancho de banda. Cada item debe ser eliminable individualmente, y la acción de borrar debe ser un botón enfocable y etiquetado (con aria-label="Quitar foto.jpg"), no una X muda, para cumplir WCAG 2.4.6 (Labels).

Eleken "File Upload UI" · Uploadcare UX · WCAG 1.4.3 Contrast · WCAG 2.4.6 Labels
Preferir
portada.jpg
2.1 MB
planos.pdf
680 KB
detalle.png
1.4 MB
Evitar
IMG_0421.jpg
IMG_0422.jpg
Captura 2026-06-18.png
796

Errores por archivo con reintento, nunca falles todo el lote

Cuando un archivo falla (timeout de red, error de servidor, tipo rechazado), solo su fila entra en estado de error con un mensaje específico y acción de reintentar; el resto de la cola sigue subiendo sin interrupción. WCAG 3.3.1 y 3.3.3 piden identificar el error en texto y sugerir la corrección. Ofrece un "Reintentar" para problemas temporales como timeouts, o quitar el archivo y probar otro, manteniendo un tono amable. Distingue errores corregibles por el usuario ("Tipo no soportado, usa JPG o PNG") de errores de sistema ("Error del servidor, reintenta").

WCAG 3.3.1 Error Identification · Eleken "File Upload UI" · Uploadcare UX · Smashing Magazine "Offline-Friendly Upload" (2025)
Preferir
ventas_q1.csv
ventas_q2.csv
report_q4.xlsx
Error de red. Reintenta.
ventas_q3.csv
Evitar
La carga fallo. Todos los archivos se perdieron.
797

Multi-archivo en paralelo y en segundo plano: no bloquees la UI

Las cargas nunca deben bloquear la interacción del usuario con el resto de la página. Deben correr asincronas en la capa de red del navegador mientras el hilo principal queda libre para renderizar, responder a clics y actualizar la UI en tiempo real (es el estandar de la industria para mantener una interfaz responsiva). El estado de la cola debe persistir aunque el usuario cambie de pestana o se desplace: un widget flotante de estado, al estilo del panel de Google Drive, que sobreviva a la navegación, es el patrón de referencia. Navegar fuera no debe cancelar ni pedir confirmación.

Readability "JS File Upload Patterns" · Page Flows "File Upload" · Smashing Magazine "Offline-Friendly Upload" (2025)
Preferir
Subiendo 5 · 3 listos
Evitar
Carga en progreso
"Hay una subida en curso, seguro que quieres salir?" · cancela todo al navegar
798

Carga accesible: input real, label asociado y aria-live para cada cambio

Un componente de carga con estilo personalizado debe construirse sobre un <input type="file"> real con un <label> asociado por for/id, nunca reemplazado por un <div> con onclick. El rol progressbar no es una live region, así que un lector no anuncia sus cambios: hay que emparejarlo con un <div role="status" aria-live="polite"> que se actualice con texto como "67% completado". Usa polite para progreso rutinario y role="alert" (assertive) solo para errores duros. La region debe existir en el DOM antes de inyectar contenido; anadirla al vuelo es poco fiable entre lectores.

W3C ARIA25 · W3C Technique H91 · MDN aria-live · WCAG 3.3.2 Labels or Instructions
Preferir
Anunciado al lector
<label for="up">Adjuntar archivos</label>
<input type="file" id="up" multiple
  accept=".pdf,.jpg,.png">
<div role="status" aria-live="polite"
  class="sr-only"></div> // la region existe antes de inyectar "67%"
Evitar
Invisible al lector
<div class="upload-btn" onclick="...">
  Subir
</div> // sin label, sin input real, sin aria-live