<input type="file">
Los elementos <input>
con type="file"
permiten al usuario elegir uno o más archivos desde el almacenamiento de su dispositivo. Una vez seleccionados, los archivos pueden ser subidos a un servidor usando el envío de formularios, o manipulados utilizando código JavaScript y la API de archivos (File API).
Pruébalo
Valor
El atributo value
de un input de archivo contiene una cadena que representa la ruta a los archivos seleccionados. Si aún no se ha seleccionado ningún archivo, el valor es una cadena vacía (""
). Cuando el usuario selecciona múltiples archivos, el value
representa el primer archivo en la lista de archivos seleccionados. Los otros archivos pueden ser identificados utilizando la propiedad HTMLInputElement.files del input.
Nota: El valor es siempre el nombre del archivo con el prefijo C:\fakepath\
, que no es la ruta real del archivo. Esto es para prevenir que software malicioso adivine la estructura de archivos del usuario.
Atributos adicionales
Además de los atributos comunes compartidos por todos los elementos <input>
, los input de tipo file
también soportan los siguientes atributos:
accept
El valor del atributo accept
es una cadena que define los tipos de archivos que el input de archivo debería aceptar. Esta cadena es una lista separada por comas de especificadores de tipo de archivo únicos. Debido a que un tipo de archivo dado puede ser identificado de más de una manera, es útil proporcionar un conjunto completo de especificadores de tipo cuando necesitas archivos de un formato dado.
Por ejemplo, hay varias maneras de identificar archivos de Microsoft Word, por lo que un sitio que acepte archivos de Word podría usar un <input>
como este:
<input
type="file"
id="docpicker"
accept=".doc,.docx,.xml,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document" />
capture
El valor del atributo capture
es una cadena que especifica qué cámara utilizar para capturar datos de imagen o video, si el atributo accept
indica que el input debe ser de uno de esos tipos. Un valor de user
indica que se debe usar la cámara y/o micrófono orientados hacia el usuario. Un valor de environment
especifica que se debe usar la cámara y/o micrófono orientados hacia el entorno. Si este atributo falta, el agente de usuario es libre de decidir por sí mismo qué hacer. Si el modo de orientación solicitado no está disponible, el agente de usuario puede volver a su modo predeterminado preferido.
Nota: > capture
era anteriormente un atributo booleano que, si estaba presente, solicitaba que se usará el dispositivo de captura de medios del dispositivo (como la cámara o el micrófono) en lugar de solicitar una entrada de archivo.
multiple
Cuando se especifica el atributo booleano multiple
, el input de archivo permite al usuario seleccionar más de un archivo.
Atributos no estándar
Además de los atributos listados anteriormente, los siguientes atributos no estándar están disponibles en algunos navegadores. Deberías intentar evitar usarlos cuando sea posible, ya que hacerlo limitará la capacidad de tu código para funcionar en navegadores que no los implementan.
webkitdirectory
El atributo booleano webkitdirectory
, si está presente, indica que solo los directorios deberían estar disponibles para ser seleccionados por el usuario en la interfaz del selector de archivos. Consulta HTMLInputElement.webkitdirectory
para detalles adicionales y ejemplos.
Aunque originalmente implementado sólo para navegadores basados en WebKit, webkitdirectory
también se puede usar en Microsoft Edge, así como en Firefox 50 y posteriores. Sin embargo, aunque tiene un soporte relativamente amplio, aún no es estándar y no debería usarse a menos que no tengas alternativa.
Especificadores de tipo de archivo únicos
Un especificador de tipo de archivo único es una cadena que describe un tipo de archivo que puede ser seleccionado por el usuario en un elemento <input>
de tipo file
. Cada especificador de tipo de archivo único puede tomar una de las siguientes formas:
- Una extensión de nombre de archivo válida, insensible a mayúsculas, comenzando con un carácter punto ("."). Por ejemplo:
.jpg
,.pdf
o.doc
. - Una cadena de tipo MIME válida, sin extensiones.
- La cadena
audio/*
que significa "cualquier archivo de audio". - La cadena
video/*
que significa "cualquier archivo de video". - La cadena
image/*
que significa "cualquier archivo de imagen".
El atributo accept
toma una cadena que contiene uno o más de estos especificadores de tipo de archivo únicos como su valor, separados por comas. Por ejemplo, un selector de archivos que necesita contenido que puede presentarse como una imagen, incluyendo tanto formatos de imagen estándar como archivos PDF, podría verse así:
<input type="file" accept="image/*,.pdf" />
Usando inputs de archivo
Un ejemplo básico
<form method="post" enctype="multipart/form-data">
<div>
<label for="file">Elige el archivo para subir</label>
<input type="file" id="file" name="file" multiple />
</div>
<div>
<button>Enviar</button>
</div>
</form>
Esto produce el siguiente resultado:
Nota: Puedes encontrar este ejemplo en GitHub también: ver el código fuente, y también verlo funcionando en vivo.
Independientemente del dispositivo o sistema operativo del usuario, el input de archivo proporciona un botón que abre un cuadro de diálogo del selector de archivos que permite al usuario elegir un archivo.
Incluir el atributo multiple
, como se muestra arriba, especifica que se pueden elegir múltiples archivos a la vez. El usuario puede elegir múltiples archivos desde el selector de archivos de cualquier manera que su plataforma elegida permita (por ejemplo, manteniendo presionada la tecla Shift o Control y luego haciendo clic). Si solo quieres que el usuario elija un solo archivo por <input>
, omite el atributo multiple
.
Obteniendo información sobre los archivos seleccionados
Los archivos seleccionados son devueltos por la propiedad HTMLInputElement.files
del elemento, que es un objeto FileList
que contiene una lista de objetos File
. El FileList
se comporta como un arreglo, por lo que puedes verificar su propiedad length
para obtener el número de archivos seleccionados.
Cada objeto File
contiene la siguiente información:
name
-
El nombre del archivo.
lastModified
-
Un número que especifica la fecha y hora en que el archivo fue modificado por última vez, en milisegundos desde la época UNIX (1 de enero de 1970, a medianoche).
lastModifiedDate
Obsoleto-
Un objeto
Date
que representa la fecha y hora en que el archivo fue modificado por última vez. Esto está obsoleto y no debería usarse. Usa lastModified en su lugar. size
-
El tamaño del archivo en bytes.
type
-
El tipo MIME del archivo.
webkitRelativePath
Non-standard-
Una cadena que especifica la ruta del archivo relativa al directorio base seleccionado en un selector de directorios (es decir, un input de tipo
file
en el que se establece el atributowebkitdirectory
). Esto no es estándar y debe usarse con precaución.
Nota: Puedes establecer así como obtener el valor de HTMLInputElement.files
en todos los navegadores modernos; esto se agregó más recientemente a Firefox, en la versión 57 (ver el error 1384030 de Firefox).
Limitando los tipos de archivo aceptados
A menudo no querrás que el usuario pueda seleccionar cualquier tipo de archivo arbitrario; en su lugar, a menudo quieres que seleccionen archivos de un tipo o tipos específicos. Por ejemplo, si tu entrada de archivo permite a los usuarios subir una foto de perfil, probablemente querrás que seleccionen formatos de imagen compatibles con la web, como JPEG o PNG.
Los tipos de archivo aceptables se pueden especificar con el atributo accept
, que toma una lista separada por comas de extensiones de archivo permitidas o tipos MIME. Algunos ejemplos:
accept="image/png"
oaccept=".png"
: Acepta archivos PNG.accept="image/png, image/jpeg"
oaccept=".png, .jpg, .jpeg"
: Acepta archivos PNG o JPEG.accept="image/*"
: Acepta cualquier archivo con un tipo MIME deimage/*
. (Muchos dispositivos móviles también permiten al usuario tomar una foto con la cámara cuando se usa esto).accept=".doc,.docx,.xml,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document"
— Acepta cualquier cosa que huela a un documento de MS Word.
Veamos un ejemplo más completo:
<form method="post" enctype="multipart/form-data">
<div>
<label for="profile_pic">Elige el archivo para subir</label>
<input
type="file"
id="profile_pic"
name="profile_pic"
accept=".jpg, .jpeg, .png" />
</div>
<div>
<button>Enviar</button>
</div>
</form>
Esto produce un resultado similar al ejemplo anterior:
Nota: Puedes encontrar este ejemplo en GitHub también: ver el código fuente, y también verlo funcionando en vivo.
Puede parecer similar, pero si intentas seleccionar un archivo con este input, verás que el selector de archivos solo te permite seleccionar los tipos de archivo especificados en el valor accept
(la interfaz exacta difiere entre navegadores y sistemas operativos).
El atributo accept
no valida los tipos de archivos seleccionados, sino que proporciona sugerencias a los navegadores para guiar a los usuarios hacia la selección de los tipos de archivos correctos. Aún es posible (en la mayoría de los casos) que los usuarios activen una opción en el selector de archivos que les permita anular esto y seleccionar cualquier archivo que deseen, y luego elegir los tipos de archivos incorrectos.
Debido a esto, debes asegurarte de que el atributo accept
esté respaldado por una validación adecuada del lado del servidor.
Detectar cancelaciones
El evento cancel
se activa cuando el usuario no cambia su selección, volviendo a seleccionar los archivos previamente seleccionados. El evento cancel
también se activa cuando el cuadro de diálogo del selector de archivos se cierra o se cancela mediante el botón "cancelar" o la tecla de escape.
Por ejemplo, el siguiente código registrará en la consola si el usuario cierra el cuadro de diálogo sin seleccionar un archivo:
const elem = document.createElement("input");
elem.type = "file";
elem.addEventListener("cancel", () => {
console.log("Cancelado.");
});
elem.addEventListener("change", () => {
if (elem.files.length == 1) {
console.log("Archivo seleccionado: ", elem.files[0]);
}
});
elem.click();
Notas
-
No puedes establecer el valor de un selector de archivos desde un script: hacer algo como lo siguiente no tiene ningún efecto:
jsconst input = document.querySelector("input[type=file]"); input.value = "foo";
-
Cuando se elige un archivo usando un
<input type="file">
, la ruta real al archivo fuente no se muestra en el atributovalue
del input por razones obvias de seguridad. En su lugar, se muestra el nombre del archivo, conC:\fakepath\
como prefijo. Hay algunas razones históricas para esta peculiaridad, pero está soportada en todos los navegadores modernos y, de hecho, está definida en la especificación.
Ejemplos
En este ejemplo, presentaremos un selector de archivos ligeramente más avanzado que aprovecha la información del archivo disponible en la propiedad HTMLInputElement.files
, además de mostrar algunos trucos ingeniosos.
Nota: Puedes ver el código fuente completo para este ejemplo en GitHub: file-example.html (véalo en vivo también). No explicaremos el CSS; el JavaScript es el enfoque principal.
Primero, veamos el HTML:
<form method="post" enctype="multipart/form-data">
<div>
<label for="image_uploads">Elige imágenes para subir (PNG, JPG)</label>
<input
type="file"
id="image_uploads"
name="image_uploads"
accept=".jpg, .jpeg, .png"
multiple />
</div>
<div class="preview">
<p>No hay archivos seleccionados actualmente para subir</p>
</div>
<div>
<button>Enviar</button>
</div>
</form>
Esto es similar a lo que hemos visto antes: nada especial que comentar.
A continuación, vamos a recorrer el JavaScript.
En las primeras líneas del script, obtenemos referencias al input del formulario y al elemento <div>
con la clase .preview
. Luego, ocultamos el elemento <input>
; hacemos esto porque los inputs de archivos tienden a ser feos, difíciles de estilizar e inconsistentes en su diseño a través de los navegadores. Puedes activar el elemento input haciendo clic en su etiqueta, por lo que es mejor ocultar visualmente el input
y estilizar la etiqueta como un botón, para que el usuario sepa que debe interactuar con ella si quiere subir archivos.
const input = document.querySelector("input");
const preview = document.querySelector(".preview");
input.style.opacity = 0;
Nota: Se usa opacity
para ocultar el input de archivo en lugar de visibility: hidden
o display: none
, porque la tecnología asistiva interpreta los dos últimos estilos como si el input no fuera interactivo.
A continuación, añadimos un detector de eventos al input para detectar cambios en su valor seleccionado (en este caso, cuando se seleccionan archivos). El detector de eventos invoca nuestra función personalizada updateImageDisplay()
.
input.addEventListener("change", updateImageDisplay);
Cada vez que se invoca la función updateImageDisplay()
, nosotros:
-
Usamos un bucle
while
para vaciar el contenido anterior del<div>
de previsualización. -
Obtenemos el objeto
FileList
que contiene la información sobre todos los archivos seleccionados y lo almacenamos en una variable llamadacurFiles
. -
Comprobamos si no se seleccionaron archivos, verificando si
curFiles.length
es igual a 0. Si es así, imprimimos un mensaje en el<div>
de previsualización indicando que no se han seleccionado archivos. -
Si se han seleccionado archivos, iteramos a través de cada uno, imprimiendo información sobre él en el
<div>
de previsualización. Cosas a notar aquí: -
Usamos la función personalizada
validFileType()
para verificar si el archivo es del tipo correcto (por ejemplo, los tipos de imagen especificados en el atributoaccept
). -
Si lo es, nosotros:
- Imprimimos su nombre y tamaño en un elemento de lista dentro del
<div>
de previsualización (obtenido defile.name
yfile.size
). La función personalizadareturnFileSize()
devuelve una versión bien formateada del tamaño en bytes/KB/MB (por defecto, el navegador informa el tamaño en bytes absolutos). - Generamos una vista previa en miniatura de la imagen llamando a
URL.createObjectURL(file)
. Luego, insertamos la imagen en el elemento de lista también creando un nuevo<img>
y estableciendo susrc
en la miniatura.
- Imprimimos su nombre y tamaño en un elemento de lista dentro del
-
Si el tipo de archivo es inválido, mostramos un mensaje dentro de un elemento de lista diciendo al usuario que necesita seleccionar un tipo de archivo diferente.
function updateImageDisplay() {
while (preview.firstChild) {
preview.removeChild(preview.firstChild);
}
const curFiles = input.files;
if (curFiles.length === 0) {
const para = document.createElement("p");
para.textContent = "No hay archivos seleccionados actualmente para subir";
preview.appendChild(para);
} else {
const list = document.createElement("ol");
preview.appendChild(list);
for (const file of curFiles) {
const listItem = document.createElement("li");
const para = document.createElement("p");
if (validFileType(file)) {
para.textContent = `Nombre del archivo ${file.name}, tamaño del archivo ${returnFileSize(
file.size,
)}.`;
const image = document.createElement("img");
image.src = URL.createObjectURL(file);
image.alt = image.title = file.name;
listItem.appendChild(image);
listItem.appendChild(para);
} else {
para.textContent = `Nombre del archivo ${file.name}: Tipo de archivo no válido. Actualiza tu selección.`;
listItem.appendChild(para);
}
list.appendChild(listItem);
}
}
}
La función personalizada validFileType()
toma un objeto File
como parámetro, luego usa Array.prototype.includes()
para verificar si algún valor en fileTypes
coincide con la propiedad type
del archivo. Si se encuentra una coincidencia, la función devuelve true
. Si no se encuentra ninguna coincidencia, devuelve false
.
// https://developer.mozilla.org/es/docs/Web/Media/Formats/Image_types
const fileTypes = [
"image/apng",
"image/bmp",
"image/gif",
"image/jpeg",
"image/pjpeg",
"image/png",
"image/svg+xml",
"image/tiff",
"image/webp",
"image/x-icon",
];
function validFileType(file) {
return fileTypes.includes(file.type);
}
La función returnFileSize()
toma un número (de bytes, tomado de la propiedad size
del archivo actual), y lo convierte en un tamaño bien formateado en bytes/KB/MB.
function returnFileSize(number) {
if (number < 1e3) {
return `${number} bytes`;
} else if (number >= 1e3 && number < 1e6) {
return `${(number / 1e3).toFixed(1)} KB`;
} else {
return `${(number / 1e6).toFixed(1)} MB`;
}
}
Nota: Las unidades "KB" y "MB" utilizan aquí la convención de prefijo SI de 1 KB = 1000 B, similar a macOS. Los distintos sistemas representan los tamaños de archivo de forma diferente: por ejemplo, Ubuntu utiliza prefijos IEC donde 1 KiB = 1024 B, mientras que las especificaciones de RAM suelen utilizar prefijos SI para representar potencias de dos (1 KB = 1024 B). Por este motivo, utilizamos 1e3
(1000
) y 1e6
(100000
) en lugar de 1024
y 1048576
. En su aplicación, debe comunicar el sistema de unidades claramente a sus usuarios si el tamaño exacto es importante.
El ejemplo se ve así; juegue:
Resumen técnico
Especificaciones
Specification |
---|
HTML Standard # file-upload-state-(type=file) |
Compatibilidad con navegadores
BCD tables only load in the browser
Véase también
- Uso de archivos de aplicaciones web: contiene una serie de otros ejemplos útiles relacionados con
<input type="file">
y la API de archivos. - Compatibilidad de propiedades CSS