File input
Control de carga de archivos con soporte para selección mediante explorador y arrastrar y soltar.
1. Botón / Default
Mostrar HTML
<div class="gn-file-input gn-file-input--button">
<input type="file" id="file-btn-1" class="gn-file-input__control sr-only" aria-describedby="file-btn-1-desc">
<div class="gn-file-input__wrapper">
<label for="file-btn-1" class="gn-file-input__button">
<svg focusable="false" class="gn-file-input__icon" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
<path d="M13 11H21V13H13V21H11V13H3V11H11V2.99707H13V11Z" fill="currentColor"/>
</svg>
<span class="gn-file-input__button-text">Seleccionar archivo</span>
</label>
<span class="gn-file-input__text" id="file-btn-1-desc">Ningún archivo seleccionado</span>
</div>
</div>
Mostrar JS
document.addEventListener('DOMContentLoaded', () => {
window.GNDS.initFileInputs();
});
2. Botón / Con archivo (simulado)
Mostrar HTML
<div class="gn-file-input gn-file-input--button gn-file-input--has-file">
<input type="file" id="file-btn-2" class="gn-file-input__control sr-only" aria-describedby="file-btn-2-desc">
<div class="gn-file-input__wrapper">
<label for="file-btn-2" class="gn-file-input__button">
<svg focusable="false" class="gn-file-input__icon" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
<path d="M13 11H21V13H13V21H11V13H3V11H11V2.99707H13V11Z" fill="currentColor"/>
</svg>
<span class="gn-file-input__button-text">Cambiar archivo</span>
</label>
<div class="gn-file-input__file-info" id="file-btn-2-desc">
<span class="gn-file-input__file-name">documento_importante.pdf</span>
<span class="gn-file-input__file-size">(1.2 MB)</span>
</div>
</div>
</div>
Mostrar JS
document.addEventListener('DOMContentLoaded', () => {
window.GNDS.initFileInputs();
});
3. Botón / SM
Mostrar HTML
<div class="gn-file-input gn-file-input--button gn-file-input--sm">
<input type="file" id="file-btn-3" class="gn-file-input__control sr-only" aria-describedby="file-btn-3-desc">
<div class="gn-file-input__wrapper">
<label for="file-btn-3" class="gn-file-input__button">
<svg focusable="false" class="gn-file-input__icon" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
<path d="M13 11H21V13H13V21H11V13H3V11H11V2.99707H13V11Z" fill="currentColor"/>
</svg>
<span class="gn-file-input__button-text">Seleccionar archivo</span>
</label>
<span class="gn-file-input__text" id="file-btn-3-desc">Ningún archivo seleccionado</span>
</div>
</div>
Mostrar JS
document.addEventListener('DOMContentLoaded', () => {
window.GNDS.initFileInputs();
});
4. Botón / Disabled
Mostrar HTML
<div class="gn-file-input gn-file-input--button">
<input type="file" id="file-btn-4" class="gn-file-input__control sr-only" aria-describedby="file-btn-4-desc" disabled>
<div class="gn-file-input__wrapper">
<label for="file-btn-4" class="gn-file-input__button">
<svg focusable="false" class="gn-file-input__icon" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
<path d="M13 11H21V13H13V21H11V13H3V11H11V2.99707H13V11Z" fill="currentColor"/>
</svg>
<span class="gn-file-input__button-text">Seleccionar archivo</span>
</label>
<span class="gn-file-input__text" id="file-btn-4-desc">Ningún archivo seleccionado</span>
</div>
</div>
Mostrar JS
document.addEventListener('DOMContentLoaded', () => {
window.GNDS.initFileInputs();
});
5. Dropzone / Default
Mostrar HTML
<div class="gn-file-input gn-file-input--drop">
<input type="file" id="file-drop-1" class="gn-file-input__control sr-only">
<label for="file-drop-1" class="gn-file-input__dropzone">
<span class="gn-file-input__dropzone-text">
Arrastra aquí un archivo o <span class="gn-file-input__dropzone-link">selecciona desde tu dispositivo</span>
</span>
</label>
</div>
Mostrar JS
document.addEventListener('DOMContentLoaded', () => {
window.GNDS.initFileInputs();
});
6. Dropzone / Con archivo (simulado)
Mostrar HTML
<div class="gn-file-input gn-file-input--drop gn-file-input--has-file">
<input type="file" id="file-drop-2" class="gn-file-input__control sr-only">
<label for="file-drop-2" class="sr-only">Seleccionar archivo</label>
<div class="gn-file-input__dropzone" tabindex="0" aria-label="Cambiar archivo: informe_anual.pdf">
<div class="gn-file-input__file-info">
<svg focusable="false" class="gn-file-input__icon" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
<path d="M10.2002 2C11.4 2.00006 12.4289 2.42295 13.2871 3.26855C14.1454 4.1143 14.5751 5.14143 14.5752 6.34961V15.3496C14.5752 16.0496 14.3252 16.6504 13.8252 17.1504C13.3253 17.6503 12.7209 17.9003 12.0127 17.9004C11.3044 17.9004 10.7002 17.6526 10.2002 17.1582C9.7002 16.6636 9.4502 16.0605 9.4502 15.3496V6.09961H10.9502V15.3496C10.9502 15.633 11.0543 15.8795 11.2627 16.0879C11.471 16.296 11.7262 16.4004 12.0283 16.4004C12.3305 16.4004 12.5807 16.2961 12.7783 16.0879C12.976 15.8795 13.0752 15.633 13.0752 15.3496V6.34961C13.0751 5.54979 12.7955 4.8751 12.2373 4.3252C11.679 3.7752 10.9978 3.5 10.1943 3.5C9.39108 3.50008 8.71196 3.77537 8.15723 4.32617C7.60247 4.87708 7.32529 5.55178 7.3252 6.34961V15.8496C7.3252 17.1496 7.78307 18.2504 8.69922 19.1504C9.61533 20.0503 10.7245 20.5 12.0254 20.5C13.3238 20.4999 14.428 20.0503 15.3369 19.1504C16.2459 18.2504 16.7002 17.1496 16.7002 15.8496V6.09961H18.2002V15.8496C18.2002 17.5663 17.5985 19.0212 16.3955 20.2129C15.1927 21.4044 13.7343 22 12.0205 22C10.307 22 8.84598 21.4043 7.6377 20.2129C6.42935 19.0212 5.8252 17.5663 5.8252 15.8496V6.34961C5.82529 5.14143 6.25405 4.1143 7.1123 3.26855C7.97065 2.42274 9.00021 2 10.2002 2Z" fill="currentColor"/>
</svg>
<span class="gn-file-input__file-name">informe_anual.pdf</span>
<span class="gn-file-input__file-size">(2.4 MB)</span>
<button type="button" class="gn-file-input__remove" aria-label="Eliminar archivo">
<svg focusable="false" class="gn-file-input__icon" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
<path d="M18.8252 6.22461L13.0498 12L18.8252 17.7754L17.7744 18.8252L12 13.0498L6.22461 18.8252L5.1748 17.7754L10.9502 12L5.1748 6.22461L6.22461 5.1748L12 10.9502L17.7744 5.1748L18.8252 6.22461Z" fill="currentColor"/>
</svg>
</button>
</div>
</div>
</div>
Mostrar JS
document.addEventListener('DOMContentLoaded', () => {
window.GNDS.initFileInputs();
});
7. Dropzone / Dragover (simulado)
Mostrar HTML
<div class="gn-file-input gn-file-input--drop gn-file-input--dragover">
<input type="file" id="file-drop-3" class="gn-file-input__control sr-only">
<label for="file-drop-3" class="gn-file-input__dropzone">
<span class="gn-file-input__dropzone-text">Suelta el archivo aquí...</span>
</label>
</div>
Mostrar JS
document.addEventListener('DOMContentLoaded', () => {
window.GNDS.initFileInputs();
});
8. Dropzone / Error
Mostrar HTML
<div class="gn-file-input gn-file-input--drop gn-file-input--error">
<input type="file" id="file-drop-4" class="gn-file-input__control sr-only">
<label for="file-drop-4" class="gn-file-input__dropzone">
<span class="gn-file-input__dropzone-text">
Arrastra aquí un archivo o <span class="gn-file-input__dropzone-link">selecciona desde tu dispositivo</span>
</span>
</label>
</div>
Mostrar JS
document.addEventListener('DOMContentLoaded', () => {
window.GNDS.initFileInputs();
});
9. Dropzone / Disabled
Mostrar HTML
<div class="gn-file-input gn-file-input--drop">
<input type="file" id="file-drop-5" class="gn-file-input__control sr-only" disabled>
<label for="file-drop-5" class="gn-file-input__dropzone">
<span class="gn-file-input__dropzone-text">Carga deshabilitada</span>
</label>
</div>
Mostrar JS
document.addEventListener('DOMContentLoaded', () => {
window.GNDS.initFileInputs();
});
File input
¿Qué es?
El componente file-input permite al usuario seleccionar archivos desde su dispositivo. Existen dos variantes de presentación dentro del mismo componente base: mediante un botón estándar (gn-file-input--button) o mediante un área de arrastre/dropzone (gn-file-input--drop).
¿Cuándo usarlo?
- Utiliza la variante botón (
gn-file-input--button) en formularios convencionales donde el espacio es limitado o la carga de archivos es un paso menor. - Utiliza la variante dropzone (
gn-file-input--drop) en interfaces más modernas o amplias, cuando la carga de archivos es la acción principal de esa pantalla.
Variantes
gn-file-input--button: Presentación clásica con botón "Seleccionar archivo" y texto adyacente.gn-file-input--drop: Presentación en forma de caja punteada (dropzone).
Modificadores de Estado
gn-file-input--sm(solo botón): Tamaño reducido.gn-file-input--has-file: Cambia la presentación visual para mostrar la información del archivo seleccionado y la opción de descartarlo.gn-file-input--dragover(solo dropzone): Estado activo al arrastrar un archivo por encima de la zona.gn-file-input--error(solo dropzone): Borde de advertencia cuando ocurre un problema con el archivo.
Consideraciones de accesibilidad y limitaciones del navegador
Los navegadores no permiten estilizar libremente el elemento nativo <input type="file">. Por lo tanto, se ha optado por un patrón de ocultación visual (.sr-only o .gn-file-input__control) asociado a una <label> que actúa como el área clicable real.
- El foco del teclado siempre recae sobre el
inputnativo (aunque esté oculto), y mediante CSS delegamos el anillo de foco (box-shadow) al contenedor o la zona de arrastre para hacerlo visiblemente claro. - Esta estructura garantiza que los lectores de pantalla puedan interactuar nativamente con el control, indicando si hay un archivo cargado o no, pero al mismo tiempo permite un diseño 100% acorde a Figma.
- ¡Aviso! El texto simulado de los ejemplos ("Ningún archivo seleccionado" o "informe.pdf") se implementa mediante elementos
<span>separados, ya que el navegador no expone este texto a CSS.
Diferencia entre Base HTML/CSS y Comportamiento JavaScript
El componente entregado proporciona toda la estructura HTML, las clases BEM y los estilos interactivos CSS básicos (focus, hover, active). Sin embargo, hay dos aspectos que requieren JavaScript para funcionar de forma real:
- Actualización del nombre del archivo: Al seleccionar un archivo, se debe actualizar mediante JS el texto estático
span.gn-file-input__file-namepara que refleje el valor deinput.files[0].name. - Eventos reales Drag & Drop: La zona de dropzone requiere JavaScript (listeners de
dragenter,dragover,dragleave,drop) para agregar/quitar dinámicamente la clase.gn-file-input--dragovery asignar el archivo soltado alinputnativo oculto.