Saltar al contenido
menumenu tanreiexpand_morecontrasttranslate
tanreiexpand_more
Primeros pasosWebReactSwiftUIJetpack ComposeFlutterReact NativePreajustesTu propio sistema de diseñoUsar Tanrei con agentes de IAMarcaTokens de diseñoSistemas de diseño y personalizaciónTheme StudioColorTipografíaIconosFormaElevaciónMovimientoEstados de interacciónComportamientoDiseño de páginaAccesibilidadTextosTokens de colorTokens de la escala tipográficaTokens de formaTokens de elevaciónTokens de movimientoTokens de estadoTokens de espacio y de medidaComponentesBotónBotón de acción principalBotón segmentadoGrupo de botonesBotón con menúBarra de herramientasBotón de copiarCasilla de verificaciónBotón de opciónInterruptorChipMenúControl deslizanteCampo de control deslizanteCalendarioDateTimePickerGrupo de camposGrupo de botones de opciónGrupo de casillas de verificaciónSelectCampo de selecciónBarra de menúsSubida de archivosSelector de archivosZona de soltar archivosEntrada de texto AvanzadoCampo de textoCampo de chipsCampoCuadro combinado AvanzadoCampo de cuadro combinadoEntrada numérica AvanzadoCampo numéricoEntrada de color AvanzadoCampo de colorEntrada de código de un solo uso AvanzadoCampo de código de un solo usoEntrada de texto incrustada AvanzadoCuadro de redacción de chatTarjetaDivisorCapa modal AvanzadoDiálogoListaFila de listaHoja inferiorHoja lateralCarruselBloque de códigoTablaPopoverPasosAcordeónLista de descripcionesFiguraEstructura de la aplicaciónCabecera de páginaVista de árbolLínea de tiempoVista previa de imágenesTirador de tamañoMarco redimensionableÁrea de desplazamientoInsigniaIndicador de progresoMedidorContador animadoIndicador de cargaSnackbarTooltipAtajo de tecladoTagCódigo en líneaCalloutAvatarEstado vacíoGrupo de tagsEsqueletoElemento de archivoMuestraTexto en marquesinaPestañasVista de pestañasBarra de la aplicaciónBarra de navegaciónPanel de navegaciónBúsquedaEnlacePaginaciónEnlaces anterior y siguienteIndicador de pasosRuta de navegaciónTabla de contenidoTarjeta de enlaceMenú FABEstadoCómo se construye TanreiCómo contribuirLicencia y atribución
InicioComponentesSelector de archivos

Selector de archivos

Permite elegir archivos con el selector propio de la plataforma —desde un botón y, donde hay sitio, desde un lugar al que también se pueden arrastrar—, dice los límites con palabras antes de la elección, juzga lo elegido y entrega a tu producto lo que se aceptó y lo que se rechazó. No conserva nada, no enumera nada y no participa en ningún formulario.

content_copyVer en Markdown

Avanzado

La mayoría de los productos usan Chat composer, File upload, del que este componente forma parte.

Categoría
Selección
Tokens
comp.file-picker
Nivel
Base

Descripción general

Web
tanrei-file-picker
schedule
SwiftUI
TanreiFilePicker
radio_button_unchecked
Jetpack Compose
TanreiFilePicker
radio_button_unchecked
Flutter
TanreiFilePicker
radio_button_unchecked
React Native
FilePicker
radio_button_unchecked

Generado a partir de docs/status/status.json, specs/file-picker.spec.json

Un selector de archivos en cada disposición. Elegir un archivo no cambia nada aquí: la página no conserva ninguno.

Elegir un archivoElegir fotosimage

Un selector de archivos es la forma de elegir archivos, y nada más. Tu propio botón abre el selector de archivos de la plataforma. A su alrededor puede haber una zona para soltar, que además recibe los archivos que se arrastran hasta ella. Los límites aparecen al lado, con tus palabras. Lo elegido se juzga según los límites y se te entrega: los archivos aceptados, con select; los rechazados, con reject.

Es un componente avanzado: el control sin nada más, para un producto que conserva los archivos por su cuenta. No conserva ningún archivo, no dibuja ninguna lista y no envía nada con un formulario. La mayoría de los productos quieren el control de subida de archivos, que es este selector con una lista de elementos de archivo debajo, listo para usarse en un formulario.

Se usa en el control de subida de archivos. Úsalo por separado cuando los archivos van a un lugar que no es la lista del control de subida:

  • Un archivo se lee en el momento y no se conserva: importar un archivo de configuración, una hoja de cálculo con filas, una imagen para recortar.
  • Los archivos se muestran en otra parte: como adjuntos dentro de un mensaje que se está escribiendo, en un lienzo, en una tabla tuya.
  • Un botón de adjuntar sin zona y sin textos, en una barra de herramientas.

Para recibir archivos soltados en cualquier punto de una pantalla entera, envuelve la pantalla en una zona de soltar archivos, y deja un selector de archivos en esa pantalla como la forma de elegir sin arrastrar.

No conserva nada

Después de select, el selector de archivos ya ha olvidado los archivos. Una segunda elección se juzga como si fuera la primera. Si tu producto no conserva lo que select le da, nadie lo conserva.

En la web es <tanrei-file-picker>. Las demás plataformas todavía no lo han implementado.

Uso

Pon un botón en el slot trigger y escucha select.

<tanrei-field label="Archivo de capa" supporting-text="La capa sustituye a la que estás editando.">
  <tanrei-file-picker id="layer" accept=".json" constraints-text="Un archivo JSON"
                      selection-text="Ningún archivo elegido">
    <tanrei-button slot="trigger" variant="outlined">Elegir un archivo</tanrei-button>
  </tanrei-file-picker>
</tanrei-field>

<script type="module">
  import '@tanrei/web/components/field';
  import '@tanrei/web/components/file-picker';
  import '@tanrei/web/components/button';

  const picker = document.querySelector('#layer');
  picker.addEventListener('select', async ({ detail }) => {
    const [file] = detail.files;
    // El selector no conserva nada. Di tú qué se ha elegido y haz con el archivo lo que te propongas.
    picker.selectionText = file.name;
    importLayer(JSON.parse(await file.text()));
  });
  // Un archivo rechazado tiene un motivo que es un nombre, no una frase. Dilo con tus propias palabras.
  picker.addEventListener('reject', ({ detail }) => {
    const field = picker.closest('tanrei-field');
    field.errorText = detail.files[0].reason === 'type' ? 'Elige un archivo JSON.' : 'Elige un solo archivo.';
    field.error = true;
  });
</script>
// Un componente avanzado —una pieza de la que se construyen otros— se importa desde la entrada advanced.
import { Button, Field } from '@tanrei/react';
import { FilePicker } from '@tanrei/react/advanced';

<Field label="Archivo de capa" error={!!problem} errorText={problem}>
  <FilePicker accept={['.json']} constraintsText="Un archivo JSON"
    selectionText={chosen?.name ?? 'Ningún archivo elegido'}
    onSelect={(event) => importLayer(event.detail.files[0])}
    onReject={(event) => explain(event.detail.files)}>
    <Button slot="trigger" variant="outlined">Elegir un archivo</Button>
  </FilePicker>
</Field>

Los archivos que llegan a tu producto por otra vía —pegados, soltados en otra parte de la página— se juzgan con la misma regla mediante judge(). Responde y no emite nada:

const { accepted, refused } = picker.judge(event.clipboardData.files);

En React, judge() está en la ref: ref.current.judge(files).

Especificaciones

El activador solo; con lo elegido y los límites; una zona para soltar en su estado de error; deshabilitado

Adjuntar un archivoElegir un archivoElegir archivosElegir archivos

Anatomía

Parte Descripción
1 group The whole component: the trigger with its texts, or the drop area. Exposed as a named group while it has a name; it draws nothing of its own.
2 trigger The product's own Button in the trigger slot. Activating it opens the platform's own file picker. It is the one way to choose by keyboard, by touch and with assistive technology, in both layouts.
3 container · opcional The drop area, in the drop-area layout: a bounded place around the glyph, the prompt, the trigger and the line of limits, which takes files dragged onto it and opens the picker when pressed. It carries the state answer.
4 outline · opcional The drop area's edge, dashed or solid as the system says.
5 icon · opcional The glyph at the top of the drop area: the icon set's upload glyph, or the one in the icon slot. Decorative.
6 label · opcional The drop area's prompt (dropText): the words that say files can be dragged here.
7 supporting-text · opcional The line that states the limits in words (constraintsText): which kinds of file, how large, how many. In the area, or below the trigger.
8 selection-text · opcional In the button layout, the text beside the trigger that says what is chosen now (selectionText). Whoever holds the files writes it.

Propiedades

Propiedad Tipo Valor predeterminado Descripción
layout button | drop-area "button" How choosing is offered. button: the trigger alone, with the line of limits below it; for a form among other fields, a narrow place, a phone, a toolbar. drop-area: a bounded place around the trigger that also takes files dragged onto it and opens the picker when pressed; for a screen whose main task is to hand over files, where a pointer is likely. Both open the same picker from the same trigger.
multiple boolean false Whether more than one file can be chosen at a time. False: the picker offers one file, and a drop of several is refused whole. True: the picker offers several. The file picker keeps nothing, so whether a second choice adds to the first or takes its place is decided by whoever keeps the files.
accept strings The kinds of file that are taken: file name extensions with their dot (".pdf") and media types, a whole family as "image/*". The picker is asked to offer these, and a file of another kind — dropped, or chosen in a picker that did not filter — is refused (reject, reason type). Empty takes every kind. It enforces the limit; constraintsText says it.
maxSize number null The largest size of one file, in bytes. A larger file is refused (reject, reason size). Null sets no limit. It is judged from the size the platform reports; the file is not read.
maxFiles number null The most files one choice or one drop may bring, while multiple is true. Files beyond it are refused (reject, reason count). Null sets no limit; ignored while multiple is false. The file picker counts nothing across choices: a product that keeps a list sets this to the room that is left — zero once the list is full, which refuses every file — or judges the room itself.
label string "" The accessible name of the file picker as a group ("Photo"). It is not drawn. Leave it empty inside a Field, whose label names the group and is drawn, and inside a component that names the whole; left empty elsewhere, no group is exposed and the trigger stands as the button it is.
constraintsText string "" The limits, in the product's words, shown before the choice ("PDF or PNG, up to 10 MB each, 5 files at most"). Drawn in the area, or below the trigger, and given to assistive technology as the trigger's description. Tanrei builds no such sentence from accept, maxSize and maxFiles: it has no words.
dropText string "" The drop area's prompt, in the product's words ("Drag files here, or choose them"). Drawn above the trigger in the drop-area layout; ignored in the button layout.
selectionText string "" What stands beside the trigger in the button layout: what is chosen now, in the product's words or the file's own name ("No file chosen", "brief.pdf", "3 files"). Read with the trigger, as part of its description. The file picker keeps nothing and so never writes or changes it: whoever holds what was chosen says it, and leaves it empty where a list below already does. Ignored in the drop-area layout.
disabled boolean false Nothing can be chosen or dropped: the trigger is disabled and the area answers nothing. Inside a Field, disable the Field.
error boolean false Puts the file picker in the error condition: the drop area's edge is drawn in the error role and the trigger is exposed as invalid. A Field sets it with its own error; the words are the Field's errorText. The file picker never sets it itself.
required boolean false Exposes the trigger as required, where the platform's button has such a state. A Field that is required sets it. It draws nothing — the mark beside the label is the Field's — and it validates nothing: the file picker has no value that could be missing.

Slots

Slot Descripción
trigger The product's own Button that opens the picker, with the product's own label ("Choose files"), variant and size. Exactly one. The file picker gives it the behaviour and never restyles it.
icon A glyph in place of the upload glyph at the top of the drop area (a picture for a photo, a table for a spreadsheet). Decorative; ignored in the button layout.

Eventos

Evento Descripción
select Files were chosen in the picker or dropped on the area, and passed accept, maxSize and the count of one choice. Emitted once per choice, with those files as the platform's own handles, in the order the platform gave them. The file picker keeps none of them and reads none: the product, or the component that holds the file picker, does with them what it means to.
reject Files of one choice or one drop were refused. Emitted once, after select where both happen, with each refused file and its reason: type (not among accept, or a folder), size (larger than maxSize) or count (more than one while multiple is false, or more than maxFiles in one choice). The reasons are names for the product's code, not words: the product says what happened, in its own words and in a place of its own — a Field's errorText, a row of its list, a message it has announced. The file picker draws and says nothing for a refusal.

Estados

Comportamiento

Requisitos en formato EARS. Cada implementación de plataforma se prueba contra estos identificadores. El texto de los requisitos se muestra tal como está en la especificación, en inglés.

ID Requisito
FPK-1 THE file picker SHALL lay out one part, from its start edge: the trigger with its texts WHILE layout is button (FPK-2), the drop area WHILE layout is drop-area (FPK-3). It SHALL be as wide as its layout gives it and as tall as its parts, SHALL draw no container, fill or edge around the whole, SHALL draw no list and no row for what was chosen, and SHALL draw no label, no help, no error text and no requirement mark of its own: those are the Field's (FPK-21).
FPK-2 WHILE layout is button THE file picker SHALL draw the trigger at its start edge at the size the product gave it and, WHILE selectionText is not empty, selectionText after it on the trigger's line, comp.file-picker.trigger.gap from it and centred on it, in comp.file-picker.selection-text.typescale and comp.file-picker.standard.selection-text.color, wrapping below the trigger where the line is too short; and WHILE constraintsText is not empty SHALL draw it comp.file-picker.supporting-text.gap below that line, from the start edge, in comp.file-picker.supporting-text.typescale and comp.file-picker.standard.supporting-text.color, on as many lines as it needs and never cut. WHILE layout is button THE file picker SHALL draw no area, edge or glyph, SHALL ignore dropText and the icon slot, and SHALL take no drop (FPK-13). THE file picker SHALL NOT write selectionText itself and SHALL NOT change it because of a choice: it keeps nothing (FPK-7), so what is chosen now is said by whoever holds it.
FPK-3 WHILE layout is drop-area THE file picker SHALL draw the drop area across its whole width: a container with corners of comp.file-picker.container.shape, filled with comp.file-picker.standard.container.color, with an edge comp.file-picker.outline.width wide in comp.file-picker.standard.outline.color drawn inside its size, and inside it — comp.file-picker.container.padding-block from its top and bottom and comp.file-picker.container.padding-inline from its sides — one column, each part centred on the inline axis and comp.file-picker.container.gap from the next: the glyph (FPK-4), dropText WHILE it is not empty in comp.file-picker.label.typescale and comp.file-picker.standard.label.color, the trigger at the size the product gave it, and constraintsText WHILE it is not empty in comp.file-picker.supporting-text.typescale and comp.file-picker.standard.supporting-text.color. Each text SHALL be centred, wrap onto as many lines as it needs and never be cut. The area SHALL be as tall as its parts and paddings and have no height of its own. WHILE layout is drop-area THE file picker SHALL NOT draw selectionText: what was dropped on a place is shown below it, by whoever holds it.
FPK-4 THE file picker SHALL draw the drop area's edge as comp.file-picker.outline.style names: dashed, as dashes comp.file-picker.outline.dash-length long with gaps of the same length, following the corners; solid, as one unbroken line. It SHALL draw at the top of the area the icon set's upload glyph, or the glyph in the icon slot WHILE that slot holds one, at comp.file-picker.icon.size in comp.file-picker.standard.icon.color, with sys.icon.family.unselected and sys.icon.fill.unselected, sys.icon.weight and an optical size clamped between sys.icon.optical-size.min and sys.icon.optical-size.max, and SHALL keep it from assistive technology. A platform that cannot draw a dashed edge along eased corners SHALL draw it solid and state that in its README.
FPK-5 THE file picker SHALL take as its trigger the one element in the trigger slot — a Button of the product's, with the product's label, variant and size — and SHALL leave it what it is: drawn from the Button's own tokens, answering hover, focus and press itself, named by its own label. WHEN the trigger is activated, by any input the Button takes, THE file picker SHALL open the platform's own file picker (FPK-6). IF the trigger slot is empty THE file picker SHALL still render and still take drops and presses on its area, and in debug builds SHALL report that files cannot be chosen by keyboard, by touch or with assistive technology, which is a functional failure; IF it holds more than one element THE file picker SHALL use the first and report the others.
FPK-6 WHEN the picker is asked for THE file picker SHALL open the platform's own file picker — never a list of files it draws itself — asking it for one file WHILE multiple is false and for any number WHILE multiple is true, and to offer the kinds accept lists WHILE accept is not empty. WHEN the person chooses, THE file picker SHALL judge what was chosen (FPK-9) and leave focus on the trigger; WHEN the person leaves the picker without choosing THE file picker SHALL emit nothing, change nothing and leave focus on the trigger. WHILE a picker it opened is still open THE file picker SHALL NOT open a second.
FPK-7 THE file picker SHALL keep nothing and send nothing: it SHALL open no connection and send no file or part of one to anyone, SHALL NOT read a file's bytes — not to check its kind, not to measure it, not to draw a picture of it — SHALL NOT copy or store a file, and SHALL NOT hold a file, or any record of an earlier choice, beyond the turn in which it hands the files of one choice over (FPK-9): a second choice SHALL be judged as if it were the first. What is known of a file SHALL be what the platform reports of it without opening it: its name, its size and its kind. THE file picker SHALL take no part in a form: it has no name and no value, submits nothing, reports no missing value, and has nothing to reset or to restore. The files of a form are submitted by the component that keeps them, or sent by the product.
FPK-8 WHEN the drop area of the file picker is pressed by pointer or touch THE file picker SHALL show the pressed state without delay and SHALL keep it visible for at least sys.motion.duration.press-hold, even when the press ends sooner. The area answers no key (FPK-12): Enter and Space press the trigger, which answers as a Button does (BTN-8).
FPK-9 WHEN files arrive — chosen in the picker or dropped on the area — THE file picker SHALL judge them in the order the platform gave them, by what the platform reports without opening them, and keep none: WHILE multiple is false and more than one arrived, it SHALL refuse them all with the reason count, choosing none for the person; otherwise it SHALL refuse with the reason type a file whose kind matches no entry of a non-empty accept — an extension compared with the end of its name without regard to case, a media type with the kind the platform reports, a family such as image/* with every kind of that family — and anything that is a folder; SHALL refuse with the reason size a file larger than maxSize WHILE maxSize is a number; and, WHILE multiple is true and maxFiles is a number, SHALL refuse with the reason count each remaining file beyond the first maxFiles of them. It SHALL then emit select once with the files that passed, WHERE there are any, and reject once with the refused files and their reasons, WHERE there are any, in that order. THE file picker SHALL judge each arrival by itself: it knows of no earlier choice, so the room that is left in a list is judged by whoever keeps the list. THE file picker SHALL draw no row and no error and say no word because of a choice.
FPK-10 WHILE the drop area is pressed THE file picker SHALL answer as sys.behavior.pressed-feedback names: overlay applies the pressed tokens to the whole container at once; ripple grows the pressed state layer from the point of contact; dim applies the pressed opacity to the whole area and draws no state layer; none draws no answer to the press. Under ripple and dim only the container color stays with the state under the press; outline, glyph, texts, opacity and shape still come from the pressed tokens. Under none every part stays with the state under the press. The ripple grows over comp.file-picker.motion.feedback-duration with comp.file-picker.motion.state-easing, fades over comp.file-picker.motion.state-duration with comp.file-picker.motion.state-easing once the press has ended and press-hold has passed, and appears whole where motion is reduced.
FPK-11 THE file picker SHALL ease the corners of its drop area by sys.shape.corner-smoothing (0 is a quarter circle, 0.6 the iOS continuous corner; a platform with only the OS curve draws it for any amount above 0); a platform that cannot draw a choice SHALL fall back to the first value and state that in its README. THE file picker SHALL draw no focus indicator of its own: keyboard focus is on the trigger, which shows it as sys.behavior.focus-style names, as every Button does (BTN-10).
FPK-12 WHEN the person presses the drop area outside the trigger, by pointer or touch, WHILE disabled is false THE file picker SHALL do what activating the trigger does (FPK-6) and move focus to the trigger, so that the whole area is one large target for the one action. The area SHALL NOT be a stop in the focus order, SHALL have no role and no name of its own, and SHALL answer no key: Enter and Space are the trigger's. A press that begins on the trigger SHALL be the trigger's alone and open the picker once.
FPK-13 WHILE something is dragged over the drop area and disabled is false THE file picker SHALL draw the area as receiving — filled with comp.file-picker.receiving.container.color, its edge in comp.file-picker.receiving.outline.color, its glyph, its prompt and its line of limits in comp.file-picker.receiving.content.color — and tell the platform that letting go here copies; or, WHERE the platform tells before the drop that nothing dragged can be taken — it holds no file, every file is of a kind accept refuses, or it holds more than one file while multiple is false — as refusing: the fill and the texts as at rest, the edge in comp.file-picker.refusing.outline.color, and the icon set's block glyph in the glyph's place in comp.file-picker.refusing.icon.color, telling the platform that letting go here does nothing. The condition SHALL begin when the drag enters the area's bounds and end when it leaves them or ends, not when it crosses a part inside the area; the trigger and the texts SHALL NOT answer the drag themselves; and a drag elsewhere on the page or the screen SHALL change nothing: the file picker watches no more than its own area. WHILE layout is button THE file picker SHALL take no drop and SHALL leave a drag over it to the platform and the product.
FPK-14 WHEN files are let go over the drop area WHILE disabled is false THE file picker SHALL end the condition of FPK-13 at once, take the drop so that the platform does not open or navigate to the file, and judge what was dropped exactly as a choice in the picker (FPK-9): a drop over a refusing area SHALL emit reject with what it holds and no select, and a drop that holds no file SHALL emit nothing. It SHALL NOT move focus because of a drop. WHILE disabled is true THE file picker SHALL draw neither condition, tell the platform that letting go here does nothing, and still take a drop over its area so that a file let go by mistake does not replace the page.
FPK-15 WHILE the pointer is over the drop area, or the area is pressed (FPK-12), THE file picker SHALL render the area's container, edge, glyph, prompt, line of limits and opacity from the component tokens of the highest-precedence active state, with precedence pressed over hovered, and the pointer over the trigger counts as over the area. THE drop area SHALL have no focused state: keyboard focus is on the trigger, which shows its own indicator. Among conditions, disabled SHALL win over refusing and receiving, which win over hovered and pressed; the error condition (FPK-16) SHALL change the edge alone and combine with every state.
FPK-16 WHILE error is true THE file picker SHALL draw the drop area's edge in comp.file-picker.standard.error.outline.color, in every state, and every other part as without the error; SHALL expose the trigger as invalid; and WHILE layout is button SHALL draw nothing for it, because the error is said by the words of the Field around it. THE file picker SHALL never set error itself: not for a refused file and not for a picker that was left without a choice. WHILE something is dragged over the area the conditions of FPK-13 SHALL be drawn in the error edge's place.
FPK-17 WHILE label is not empty, or a Field names it (FPK-21), THE file picker SHALL expose itself to assistive technology as a group of that name holding the trigger; WHILE neither gives a name THE file picker SHALL expose no group and no role of its own, and SHALL report nothing: its trigger is a button with a name of its own, and a component that holds the file picker names the whole itself. It SHALL give the trigger, after any description the trigger has of its own, a description made of constraintsText, then selectionText WHILE it is drawn (FPK-2), then what a Field or the component that holds it gives (FPK-21), and SHALL expose the trigger as required WHILE required is true and as invalid WHILE error is true. It SHALL NOT expose the drop area, its glyph or dropText as controls: dropText is read as the text it is, before the trigger. THE file picker SHALL have no live region and SHALL announce nothing: a choice is said by whoever keeps it.
FPK-18 THE file picker SHALL have no words of its own: it SHALL take every word it draws or says — the trigger's label, label, constraintsText, dropText and selectionText — from the product alone, by the trigger and the props of the instance, and SHALL read none of them from the product's words by a key, because none is said the same way wherever a file picker stands. IF dropText or selectionText is not given THE file picker SHALL draw nothing in its place. IF accept is not empty, or maxSize or maxFiles is a number, WHILE constraintsText is empty THE file picker SHALL still render and in debug builds report that a limit is enforced and not said. THE file picker SHALL build no sentence from accept, maxSize, maxFiles, a count of files or a size in bytes.
FPK-19 WHILE disabled is true THE file picker SHALL disable its trigger as that Button's own disabled does and give it back as it was WHEN disabled becomes false, never enabling a trigger the product disabled itself; SHALL render the drop area's container, edge, glyph, prompt and line of limits, and selectionText, from their disabled tokens; SHALL NOT answer a press on the area (FPK-12) or a drag over it (FPK-14); and SHALL emit neither select nor reject. The way of FPK-31 SHALL still answer: disabled stops the person, not the product.
FPK-20 WHEN the colors of the drop area change between states or conditions THE file picker SHALL animate the change over comp.file-picker.motion.state-duration with comp.file-picker.motion.state-easing, and SHALL change them at once where motion is reduced. WHEN selectionText appears, changes or leaves THE file picker SHALL draw that at once, without a motion of its own.
FPK-21 WHILE the file picker is the control of a Field THE file picker SHALL take from it what a Field gives its control (FLD-8, FLD-10, FLD-11, FLD-14): the Field's label as its group's name WHILE its own label is empty; the Field's supporting text with, in error, the error text after it and optional text as the last part of the trigger's description; the invalid state as its own error condition (FPK-16); the required state as required; and the disabled state as disabled. WHEN the label of the Field is pressed THE file picker SHALL move focus to its trigger and open nothing. WHILE another component holds the file picker as its member THE file picker SHALL take the same from that component by the same exchange — a name or none, a description, and the three states, each as a value — so that it is tied inside a component exactly as it is tied by hand.
FPK-22 WHILE the text size is enlarged THE file picker SHALL grow with its texts: the prompt, the line of limits and selectionText wrap and are never cut; the glyph keeps its box; the area grows in height; and the trigger grows as the Button says. At 200 % in a width of 320 no text SHALL be lost or lie over another part, and nothing SHALL need scrolling in two directions.
FPK-23 WHERE the platform draws with a person's own forced colors (the web's forced-colors mode, and a platform's equivalent where it has one) THE file picker SHALL draw the drop area's edge and its texts in the platform's text color and no fill; SHALL draw the receiving area with an edge twice comp.file-picker.outline.width wide, solid, in the platform's highlight color, and the refusing area with its block glyph, so that neither rests on a fill the mode removes; and SHALL draw disabled parts in the platform's disabled text color.
FPK-24 WHERE the layout direction is right-to-left THE file picker SHALL mirror its layout: the trigger at the right, selectionText after it toward the left, and the line of limits from the right edge. The drop area's column stays centred. A ripple SHALL still grow from the point of contact.
FPK-25 THE file picker SHALL take its layout direction from where it is used — the direction of the nearest ancestor that sets one, and the platform's own where none does — and SHALL have no direction setting of its own; WHEN that direction changes while the file picker is shown THE file picker SHALL draw itself for the new direction at once, without a motion of its own, keeping its focus.
FPK-26 THE file picker SHALL lay out each text it draws — the prompt, the line of limits and selectionText — as text of its own direction, isolated from the text around it: each takes the base direction of its first strong character, or the layout direction where it has none, so that a file's name given as selectionText keeps its order, its dot and its extension in a right-to-left layout. WHERE the layout direction is right-to-left a glyph SHALL be mirrored exactly when the system's icon set marks its name as mirrored or the product forces it, by the icon helper and inside its own box; THE file picker SHALL mirror no glyph itself.
FPK-27 WHEN layout names a value the file picker does not know THE file picker SHALL behave as button; IF maxSize is not a number above zero THE file picker SHALL set no limit of size; IF maxFiles is not a whole number of zero or more THE file picker SHALL set no limit of count; IF an entry of accept is neither an extension with its dot nor a media type THE file picker SHALL ignore that entry; and in each case debug builds SHALL report it. WHILE maxFiles is zero and multiple is true THE file picker SHALL refuse every file that arrives with the reason count and report nothing: zero is the room a full list has left, and to read it as no limit would open the list when it is full.
FPK-28 WHEN a prop of the file picker changes while it is shown THE file picker SHALL draw and expose the new value at once, keeping its focus, and SHALL announce nothing. WHEN accept, maxSize, maxFiles or multiple changes THE file picker SHALL judge by the new value from the next arrival on. WHEN layout changes while something is dragged over the area THE file picker SHALL end the condition.
FPK-29 WHILE the system's icon set cannot yet draw a glyph of the file picker (its font is still loading) THE file picker SHALL draw nothing in that glyph's place, never the glyph's name as text, SHALL keep the glyph's box, and SHALL draw the glyph once the set can.
FPK-30 IF the trigger slot holds an element that is not a Button THE file picker SHALL still open the picker when that element is activated by a press or a click, and in debug builds report it; IF the file picker holds a child that is neither its trigger nor its glyph THE file picker SHALL NOT draw it and in debug builds report it. A platform that cannot inspect its content SHALL state the rule in its README and docs page.
FPK-31 THE file picker SHALL offer the product, and a component that holds it, a way in the platform's idiom to have files judged that came neither through its picker nor onto its area — files pasted, dropped on another part of the product's screen, or made by the product: it SHALL judge them as one arrival by the rule of FPK-9 and answer with the files that passed and with the refused files and their reasons, each in the order given; SHALL emit neither select nor reject for them, as a control's events tell what a person did; and SHALL keep none of them (FPK-7).
FPK-32 WHERE the platform has ARIA attributes (the web), WHEN the product sets an aria- attribute on the host, by the attribute or by the ARIA property that reflects it, THE file picker SHALL move it to the data-aria- attribute of the same name, so that the host is no second node with its name, description or state, and SHALL expose it on its group (FPK-17), which it SHALL be WHILE it has a name: its label or its Field's, or one given so — an id reference by the elements it names in the host's tree or a tree around it, a description after its own. WHILE label, or the Field's label, is not empty it is the group's name, over a name given so. WHEN the product removes the aria- attribute or its data-aria- twin, or sets the ARIA property that reflects it (ariaLabel, ariaDescribedByElements…) to null, THE file picker SHALL take it off that element.

Correspondencia de nombres por plataforma

Paridad no significa API idénticas. Cada plataforma expresa el mismo contrato con su propio estilo.

Especificación Web SwiftUI Jetpack Compose Flutter React Native
Componente tanrei-file-picker TanreiFilePicker TanreiFilePicker TanreiFilePicker FilePicker
layout · Propiedad layout layout layout layout layout
multiple · Propiedad multiple allowsMultipleSelection multiple multiple multiple
accept · Propiedad accept allowedContentTypes mimeTypes accept accept
maxSize · Propiedad maxSize maxSize maxSize maxSize maxSize
maxFiles · Propiedad maxFiles maxFiles maxFiles maxFiles maxFiles
label · Propiedad label label contentDescription semanticLabel accessibilityLabel
constraintsText · Propiedad constraintsText constraintsText constraintsText constraintsText constraintsText
dropText · Propiedad dropText dropText dropText dropText dropText
selectionText · Propiedad selectionText selectionText selectionText selectionText selectionText
disabled · Propiedad disabled disabled enabled enabled disabled
error · Propiedad error isError isError isError error
required · Propiedad required isRequired required required required
select · Evento select onSelect onSelect onSelect onSelect
reject · Evento reject onReject onReject onReject onReject
Notas The shadow-root form: a control whose parts and states are its own. <tanrei-file-picker accept=".json" constraints-text="…"><tanrei-button slot="trigger" variant="outlined">Choose a file</tanrei-button></tanrei-file-picker>. Attributes are kebab-case (max-size, max-files, constraints-text, drop-text, selection-text); accept is a comma-separated list, the form a native file input takes. The trigger and the glyph stay in the product's light DOM (the trigger and icon slots); the area and the texts are in the shadow root. The picker is a real <input type="file"> in the shadow root — hidden from sight, from the focus order and from assistive technology — carrying multiple and accept, whose click() the trigger's click and a press on the area call (both are user activations); its change and the area's drop feed FPK-9, and its value is cleared after each choice so that the same file can be chosen twice. The area listens for dragenter, dragover, dragleave and drop on itself only, counts enters and leaves so that a child does not end the condition, sets dropEffect to copy or none, and during a drag knows what the browser tells: kinds and a count (DataTransfer.items), never names or sizes, so a file that is too large is refused at the drop. select and reject are CustomEvents that bubble: detail.files is a File[], and reject's detail.files is { file, reason }[]. judge(files: Iterable<File>): { accepted: File[], refused: { file: File, reason: 'type' | 'size' | 'count' }[] } is FPK-31 and dispatches nothing. **Not form-associated**: no name, no value, no validity (FPK-7). It is a Field's control: it asks for the Field's connection as every Tanrei control does and takes the name, the description and the three states as values; a component that holds it gives the same values through the same connection. The description, aria-invalid and disabled are written on the slotted trigger's host — which a tanrei-button carries to its native button — and taken back when the trigger leaves the slot; the group's role and name are on an element of the shadow root, present only while there is a name (FPK-17). A button's role has no required state, so required is said only by a Field's required text in that description. Parts: container, icon, label, supporting-text, selection-text. Custom properties: --<namespace>-comp-file-picker-…. Without script, and until the element is defined, the trigger is a button that opens nothing. Class TanreiFilePicker. React: FilePicker, with onSelect, onReject, and a ref with judge(). TanreiFilePicker(layout: .dropArea, onSelect: { urls in … }) { TanreiButton("Choose files") { } }. The picker is fileImporter(isPresented:allowedContentTypes:allowsMultipleSelection:); accept is a list of UTType (an extension or a media type is resolved to one), and the files are security-scoped URLs the product opens and releases — the view holds none after onSelect returns (FPK-7). The drop area is dropDestination(for: URL.self) with its isTargeted binding for the receiving condition; SwiftUI tells the kinds before the drop, not sizes. With VoiceOver the area is a drop point named by dropText. disabled follows .disabled(_:) and the environment; a Field's name, description and states arrive through the environment, and a view that holds the picker sets the same environment values. FPK-31 is TanreiFilePicker.judge(_:accept:maxSize:maxFiles:multiple:), a static function of the limits, since a view has no instance to call. No form. TanreiFilePicker(onSelect = { uris -> … }, trigger = { TanreiButton(onClick = {}) { Text("Choose files") } }). The picker is rememberLauncherForActivityResult with OpenDocument or OpenMultipleDocuments; accept is given as MIME types (an extension is resolved through MimeTypeMap), and the files are content Uris whose name and size come from the resolver's metadata, not from reading them. The drop area is Modifier.dragAndDropTarget, which is meaningful on large screens and with a pointer; on a phone the drop-area layout is still drawn and still pressed. disabled is the inverse flag enabled. The group is semantics(mergeDescendants = false) { contentDescription }, set only while there is a name. FPK-31 is rememberTanreiFilePickerState().judge(uris), or the top-level judgeFiles(uris, limits) it calls. No form. The framework has no file picker and no drop target for files; both are plugins, and the package depends on none. TanreiFilePicker(trigger: TanreiButton(…), onPick: (request) async => …, onSelect: …): onPick is the product's function that opens whatever picker it uses with the request's multiple and accept and returns the files as TanreiPickedFile(name, size, mimeType, handle); the file picker judges them by FPK-9 and emits. Drops arrive the same way: the product's drop plugin calls TanreiFilePickerController.dragEntered / dragExited / dropped(files), and without it the drop-area layout is drawn and pressed and takes no drop — the README says so. TanreiFilePickerController.judge(files) is FPK-31. disabled is the inverse flag enabled. No form: it is no FormField. React Native has no file picker of its own; the package depends on no picker library. <FilePicker trigger={<Button label="Choose files" />} onPick={async ({ multiple, accept }) => files} onSelect={…} />: onPick is the product's function that opens its picker and returns { name, size, type, uri }[]; the file picker judges them by FPK-9 and emits. No drop of files on phones: the drop-area layout is drawn and pressed and takes no drop, and the README says so. A ref holds judge(files) (FPK-31). No form.

Tokens

Token Alias de Valor resuelto (claro)
--tanrei-comp-file-picker-container-gap sys.space.space150 12px
--tanrei-comp-file-picker-container-padding-block sys.space.space400 32px
--tanrei-comp-file-picker-container-padding-inline sys.space.space200 16px
--tanrei-comp-file-picker-container-shape sys.shape.corner.medium 8px
--tanrei-comp-file-picker-disabled-opacity — 1
--tanrei-comp-file-picker-focused-opacity — 1
--tanrei-comp-file-picker-hovered-opacity — 1
--tanrei-comp-file-picker-icon-size sys.icon.large 32px
--tanrei-comp-file-picker-motion-feedback-duration sys.motion.role.feedback 450ms
--tanrei-comp-file-picker-motion-state-duration sys.motion.role.state.large 250ms
--tanrei-comp-file-picker-motion-state-easing sys.motion.easing.state cubic-bezier(0.2, 0, 0, 1)
--tanrei-comp-file-picker-outline-dash-length sys.space.space50 4px
--tanrei-comp-file-picker-outline-style — 0
--tanrei-comp-file-picker-outline-width sys.border.hairline 1px
--tanrei-comp-file-picker-pressed-opacity — 1
--tanrei-comp-file-picker-receiving-container-color sys.color.secondary-container #eeeeee
--tanrei-comp-file-picker-receiving-content-color sys.color.on-secondary-container #262626
--tanrei-comp-file-picker-receiving-outline-color sys.color.on-secondary-container #262626
--tanrei-comp-file-picker-refusing-icon-color sys.color.error #cd262f
--tanrei-comp-file-picker-refusing-outline-color sys.color.error #cd262f
--tanrei-comp-file-picker-standard-container-color — #000000 · 0%
--tanrei-comp-file-picker-standard-disabled-container-color — #1b1b1b · 12%
--tanrei-comp-file-picker-standard-disabled-error-outline-color — #1b1b1b · 38%
--tanrei-comp-file-picker-standard-disabled-icon-color — #1b1b1b · 38%
--tanrei-comp-file-picker-standard-disabled-label-color — #1b1b1b · 38%
--tanrei-comp-file-picker-standard-disabled-outline-color — #848484
--tanrei-comp-file-picker-standard-disabled-selection-text-color — #1b1b1b · 38%
--tanrei-comp-file-picker-standard-disabled-state-layer-color — #1b1b1b · 38%
--tanrei-comp-file-picker-standard-disabled-supporting-text-color — #1b1b1b · 38%
--tanrei-comp-file-picker-standard-error-outline-color sys.color.error #cd262f
--tanrei-comp-file-picker-standard-focused-container-color — #1b1b1b · 10%
--tanrei-comp-file-picker-standard-focused-error-outline-color — #cd262f
--tanrei-comp-file-picker-standard-focused-icon-color — #4b4b4b
--tanrei-comp-file-picker-standard-focused-label-color — #1b1b1b
--tanrei-comp-file-picker-standard-focused-outline-color — #848484
--tanrei-comp-file-picker-standard-focused-selection-text-color — #4b4b4b
--tanrei-comp-file-picker-standard-focused-state-layer-color — #1b1b1b
--tanrei-comp-file-picker-standard-focused-supporting-text-color — #4b4b4b
--tanrei-comp-file-picker-standard-hovered-container-color — #1b1b1b · 8%
--tanrei-comp-file-picker-standard-hovered-error-outline-color — #cd262f
--tanrei-comp-file-picker-standard-hovered-icon-color — #4b4b4b
--tanrei-comp-file-picker-standard-hovered-label-color — #1b1b1b
--tanrei-comp-file-picker-standard-hovered-outline-color — #848484
--tanrei-comp-file-picker-standard-hovered-selection-text-color — #4b4b4b
--tanrei-comp-file-picker-standard-hovered-state-layer-color — #1b1b1b
--tanrei-comp-file-picker-standard-hovered-supporting-text-color — #4b4b4b
--tanrei-comp-file-picker-standard-icon-color sys.color.on-surface-variant #4b4b4b
--tanrei-comp-file-picker-standard-label-color sys.color.on-surface #1b1b1b
--tanrei-comp-file-picker-standard-outline-color sys.color.outline #848484
--tanrei-comp-file-picker-standard-pressed-container-color — #1b1b1b · 10%
--tanrei-comp-file-picker-standard-pressed-error-outline-color — #cd262f
--tanrei-comp-file-picker-standard-pressed-icon-color — #4b4b4b
--tanrei-comp-file-picker-standard-pressed-label-color — #1b1b1b
--tanrei-comp-file-picker-standard-pressed-outline-color — #848484
--tanrei-comp-file-picker-standard-pressed-selection-text-color — #4b4b4b
--tanrei-comp-file-picker-standard-pressed-state-layer-color — #1b1b1b
--tanrei-comp-file-picker-standard-pressed-supporting-text-color — #4b4b4b
--tanrei-comp-file-picker-standard-selection-text-color sys.color.on-surface-variant #4b4b4b
--tanrei-comp-file-picker-standard-state-layer-color comp.file-picker.standard.label.color #1b1b1b
--tanrei-comp-file-picker-standard-supporting-text-color sys.color.on-surface-variant #4b4b4b
--tanrei-comp-file-picker-supporting-text-gap sys.space.space100 8px
--tanrei-comp-file-picker-trigger-gap sys.space.space150 12px
--tanrei-comp-file-picker-label-typescale sys.typescale.body 400 14px/1.5714
--tanrei-comp-file-picker-selection-text-typescale sys.typescale.body 400 14px/1.5714
--tanrei-comp-file-picker-supporting-text-typescale sys.typescale.body-small 400 13px/1.5385

Fixtures

Representaciones canónicas. Todas las plataformas capturan cada fixture con el mismo identificador para poder comparar los resultados.

Generado a partir de specs/file-picker.spec.json, tokens/comp/file-picker.tokens.json, design/tokens/

Pautas

Dos disposiciones

Disposición Úsala para Qué dibuja
button (la predeterminada) Un formulario, junto a otros campos; un lugar estrecho; un teléfono; una barra de herramientas. El activador, el texto que hay a su lado y dice qué se ha elegido y, debajo, los límites. No recibe nada que se suelte.
drop-area Una pantalla cuya tarea principal es entregar archivos, donde es probable que haya un puntero. Una zona delimitada alrededor del mismo activador, con un glifo y una invitación. Recibe los archivos que se arrastran hasta ella, y una pulsación en cualquier punto de ella abre el selector.

Las dos abren el mismo selector desde el mismo botón. Arrastrar es un añadido y nunca la única forma: el activador es la manera de elegir archivos con el teclado, con el tacto y con tecnología de apoyo.

El activador

El activador es tu propio botón, con tu etiqueta, tu variante y tu tamaño. Pon exactamente uno en el slot trigger. El selector de archivos le da el comportamiento y nunca cambia su estilo.

  • Un selector de archivos sin activador sigue recibiendo lo que se suelta en la disposición con zona para soltar, y una compilación de depuración lo notifica como un fallo.
  • Cualquier otra cosa que pongas dentro, aparte del activador y de un glifo en el slot icon, no se dibuja. Una compilación de depuración lo notifica.
  • El slot icon sustituye el glifo de subida que hay en la parte superior de la zona para soltar: una imagen para fotos, una tabla para una hoja de cálculo. Es decorativo, y se ignora en la disposición de botón.

Lo que se ha elegido

selectionText es el texto que aparece junto al activador en la disposición de botón: «Ningún archivo elegido», después «brief.pdf», después «3 archivos». El selector de archivos no conserva ningún archivo, así que no puede escribir ese texto. Lo escribe quien conserva los archivos: tú, o el control de subida de archivos, que lo rellena por ti.

Déjalo vacío y ahí no se dibuja nada, lo que conviene a un botón de adjuntar cuyos archivos aparecen en otra parte.

Di los límites

accept, maxSize, maxFiles y multiple hacen cumplir los límites. constraintsText los dice. Da ambas cosas.

Propiedad El límite Un archivo que lo incumple
accept Los tipos de archivo que se admiten: extensiones de archivo con su punto (.pdf) y tipos de medio, o una familia entera como image/*. Se rechaza con el motivo type. Una carpeta también se rechaza con type.
maxSize El tamaño máximo de un archivo, en bytes. Se rechaza con el motivo size.
multiple Si una elección puede traer más de un archivo. Sin él, varios archivos que llegan juntos se rechazan todos, con el motivo count. No se elige ninguno en lugar de la persona.
maxFiles El máximo de archivos que puede traer una elección o una acción de soltar, con multiple. Los archivos que lo superan se rechazan con el motivo count. Cero rechaza todos los archivos.
  • Escribe los límites como los leería una persona: «PDF o PNG, hasta 10 MB cada uno». Tanrei no construye ninguna frase a partir de accept ni de un número de bytes, porque no incluye textos propios.
  • Los límites se dibujan en el selector de archivos y no en la ayuda de un campo. La ayuda de un campo cede su lugar al texto de error, que es justo cuando una persona necesita volver a leer los límites.
  • select se emite una vez por elección con los archivos aceptados, y después reject una vez con cada archivo rechazado y su motivo. El selector de archivos no dibuja ni dice nada por un rechazo. Di qué ocurrió con tus propias palabras: el texto de error de un campo, una fila de tu lista, un mensaje que anuncias.
  • Los límites son los de una elección. El selector de archivos no sabe qué conservaste antes: define maxFiles con el número de archivos que aún caben, o juzga tú el total. El control de subida de archivos lo hace.
  • Mientras algo se arrastra sobre la zona, un navegador dice los tipos y un recuento, nunca nombres ni tamaños. Por eso, un archivo demasiado grande se rechaza al soltarlo, no mientras se sostiene.

En un campo

Pon el selector de archivos en un campo cuando el formulario muestre una etiqueta, una ayuda, un error o una marca de obligatorio. El campo los dibuja y se los da al selector de archivos, cuyo activador recibe entonces de ellos su nombre y su descripción.

<tanrei-field label="Archivo adjunto" required required-text="Obligatorio"
              error error-text="Elige un PDF de 10 MB como máximo.">
  <tanrei-file-picker accept=".pdf" max-size="10000000"
                      constraints-text="PDF, hasta 10 MB" selection-text="Ningún archivo elegido">
    <tanrei-button slot="trigger" variant="outlined">Elegir un archivo</tanrei-button>
  </tanrei-file-picker>
</tanrei-field>

Un selector de archivos no envía nada. No tiene name ni valor, y required solo informa a la tecnología de apoyo. Decir si falta un archivo le corresponde al componente que conserva los archivos: tu código, o un control de subida de archivos, que sí es un control de formulario. required, como lo dice un campo, es lo mismo que required.

De derecha a izquierda

En un diseño de derecha a izquierda, el activador está a la derecha, con el texto de lo elegido a su izquierda, y los límites empiezan desde el borde derecho. La columna de la zona para soltar sigue centrada. El nombre de un archivo que se da como selectionText conserva su propio orden, con su punto y su extensión. Un glifo solo se refleja donde el conjunto de iconos lo marca.

Recomendado

  • Conserva lo que select te da, de inmediato.
  • Di qué se ha elegido: con selectionText, o en el lugar donde tu producto muestra los archivos.
  • Di con palabras cada rechazo, donde la persona está mirando.
  • Usa el control de subida de archivos cuando los archivos se enumeran debajo del selector y se envían con un formulario.

Evita

  • No uses la zona para soltar como la única forma de elegir. Siempre contiene el activador.
  • No esperes que un formulario envíe lo elegido. El selector de archivos no participa en ningún formulario.
  • No cambies el estilo del activador solo para este lugar metiéndote en su interior. Es tu botón: elige su variante y su tamaño.
  • No construyas una lista de archivos dentro de él. Pon elementos de archivo debajo, o usa el control de subida de archivos.

Accesibilidad

Rol
group
Etiquetado
A group named by label, or by the label of the Field around it; with neither, no group — the trigger alone, a button named by its own label. The trigger is described by constraintsText, by selectionText while it is drawn, and by what the Field or the component that holds the file picker gives; it is exposed as required, invalid and disabled as the props say. The drop area and its glyph are not exposed; dropText is read as text.
Objetivo mínimo
El área de pulsación cumple el tamaño mínimo de objetivo aunque el tamaño visual sea menor. minimum 32px · pointer 44px · spacing 8px · touch 48px

Teclado

Teclas Acción
Tab / Shift+Tab Moves focus to the trigger. The drop area is not a stop.
Enter / Space On the trigger: opens the platform's file picker, as the Button's own activation.
The picker's own keys Inside the platform's picker everything is the platform's; leaving it without choosing returns focus to the trigger and changes nothing.

Notas

  • Dragging is never the only way (WCAG 2.5.7): the trigger opens the same picker in both layouts and is the path for keyboard, touch, switch and voice. A drop area without a trigger is reported as a functional failure (FPK-5). The area adds a larger pointer target and takes drops; it adds no role, no stop and no key (FPK-12).
  • Without script, and until the component is defined, on the web: the trigger is a button that opens nothing. A custom element cannot open the platform's picker by markup alone, and the file picker does not pretend to: a page that must take files where script does not run writes a native file input in its own form, as it would without Tanrei, and loses only the drawing.
  • The limits are words before the choice (WCAG 3.3.2): constraintsText is drawn and is the trigger's description. accept, maxSize and maxFiles enforce what it says; a product that sets them and writes no words is told so in debug builds (FPK-18).
  • A refused file must be said (WCAG 3.3.1), and only the product has the words and the place. On reject the product sets the errorText of the Field around the file picker, marks the file in a list of its own, or announces a sentence through a live region of its own. The file picker draws and says nothing for a refusal by itself, because it has no sentence for it and no row to put one on; the component built from it that keeps files draws such a row.
  • What is dragged over the area is the pointer user's own act and is not announced. The conditions are told without color too: receiving by its fill and, under forced colors, a thicker solid edge; refusing by the block glyph (FPK-13, FPK-23).
  • The file picker has no live region (FPK-17): it holds nothing whose change it could say. What was chosen is said by whoever shows it — the text beside the trigger, which is part of the trigger's description, or a list the product draws.
  • A file picker alone is no form control (FPK-7). It keeps nothing, so a value it submitted would be a file nobody can see or take back, and a required check would ask for something it cannot hold. A plain form takes the component that keeps the files and lists them; a product that draws its own list holds the files and sends them itself, or gives them to a control of its own.
  • required is a state for assistive technology alone, and a button has none on the web: there it is said by the Field's required text in the trigger's description, as for every control whose role has no required state.

Generado a partir de specs/file-picker.spec.json, tokens/sys/measure.tokens.json

De qué se encarga el componente

  • El activador es tu botón. Lo describen los límites y el texto que dice qué se ha elegido y, dentro de un campo, la ayuda o el error del campo.
  • Con un label, o dentro de un campo, el selector de archivos es un grupo con ese nombre. Sin nombre no expone ningún grupo: un botón de adjuntar en una barra de herramientas es solo un botón.
  • La zona para soltar es un único objetivo del puntero, grande, para ese mismo botón. No tiene rol, ni nombre, ni parada en el orden del foco, ni tecla.
  • error expone el activador como no válido y dibuja el borde de la zona con el rol de color de error. disabled deshabilita el activador, y la zona no responde a nada.
  • El selector de archivos no anuncia nada. No tiene región activa: lo que se eligió o se rechazó lo dice quien conserva los archivos.
  • Con el texto al 200%, todos los textos saltan de línea y nada se corta. En colores forzados, la zona conserva un borde, y una zona que está recibiendo un arrastre tiene uno más grueso.

Cómo está construido en la web: el selector es un <input type="file"> real en el shadow root, apartado de la vista, del orden del foco y de la tecnología de apoyo. El activador y el glifo se quedan en tu DOM. select y reject se propagan hacia arriba; detail.files es un File[] y, en reject, una lista de { file, reason }.

Carencias conocidas en la web:

  • Un botón no tiene estado obligatorio. Dentro de un campo, el texto de obligatorio del campo se suma a la descripción del activador.
  • Un navegador no entrega lo que se suelta en una zona que rechaza el arrastre. Entonces reject solo se emite por lo que no se podía saber antes de soltar, como un archivo demasiado grande.
  • En Safari, un clic no da el foco a un botón. Después de elegir allí un archivo con el puntero, el foco está donde estaba antes.
  • Un borde discontinuo no puede seguir una esquina suavizada. En un sistema de diseño que define un suavizado de esquinas, el borde se dibuja continuo donde el navegador dibuja esa curva.
  • Sin script, y hasta que el elemento está definido, el activador es un botón que no abre nada. Una página que debe recibir archivos donde no se ejecutan scripts escribe un <input type="file"> nativo.

Qué debes hacer tú

  • Pon un botón en el slot trigger, con una etiqueta que diga qué hace.
  • Da al selector de archivos un label, o ponlo en un campo, siempre que sea algo más que un botón suelto.
  • Da constraintsText siempre que definas accept, maxSize o maxFiles.
  • Di qué se ha elegido, y di cada rechazo, con palabras.
  • Anuncia lo que se añadió en una región activa tuya cuando los archivos aparezcan en un lugar al que la persona no está mirando.