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 archivos AvanzadoZona 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
InicioComponentesCampo de texto

Campo de texto

Permite introducir y editar texto (una línea, o varias que siguen al texto o cuyo tamaño se cambia a mano) o una fecha o una hora que se introducen unidad por unidad en el formato de la configuración regional, o código que se conserva exactamente como se escribe, con una etiqueta que puede decir si el campo es obligatorio u opcional, iconos opcionales, prefijo y sufijo, texto de apoyo, un recuento de caracteres y un botón de selector.

content_copyVer en Markdown
Categoría
Entradas de texto
Tokens
comp.field
Nivel
Compuesto
Se compone de
Field, Text input

Descripción general

Web
tanrei-text-field
schedule
SwiftUI
TanreiTextField
schedule
Jetpack Compose
TanreiTextField
schedule
Flutter
TanreiTextField
schedule
React Native
TextField
schedule
Variantes que no se incluyen en
tanrei: filled, outlined

Generado a partir de docs/status/status.json, specs/text-field.spec.json

Una especificación revisada que aún no está en todas las plataformas

Esta página describe el campo de texto tal como lo define ahora la especificación: una variante stacked, la predeterminada, con la etiqueta encima del campo; filled y outlined, que se conservan solo para los preajustes de Material y cupertino; alturas de 32, 40 y 56 (40, 48 y 56 en un campo filled u outlined, cuya etiqueta flota dentro); tipos de fecha y hora, con un botón de selector; un campo de varias líneas que sigue a su texto o cuyo tamaño se cambia con un tirador (resize); una fecha o una hora que se introducen unidad por unidad, en segmentos; y required y optional, que marcan un campo como obligatorio u opcional. El componente web ya hace todo esto, y las demostraciones también. Un campo también puede contener código (type="code", y wrap para sus líneas): la web ya lo ha construido, y ninguna otra plataforma todavía. El campo de texto es un campo alrededor de una entrada de texto, tal como lo describe esta página: la web también lo ha construido ya, y en ella el atributo required ha desaparecido. SwiftUI, Compose, Flutter y React Native aparecen arriba como rezagados: hasta que se pongan al día ofrecen la revisión anterior, outlined de forma predeterminada con alturas de 36 y 40, con un indicador required que no dibuja ninguna marca, y sin variante stacked, sin tipos de fecha ni de hora, sin botón de selector y sin modos de cambio de tamaño, y sus ejemplos muestran esa revisión.

Stacked, la predeterminada: un campo obligatorio y una fecha con su botón de selector

Usa un campo de texto siempre que un formulario pida texto: es el caso corriente, listo para usarse, con una etiqueta, la caja, una línea de ayuda, las palabras para un valor incorrecto y un recuento.

Se compone de un campo y una entrada de texto. El campo es el marco: la etiqueta, la marca de obligatorio o de opcional, la ayuda, el error y el recuento. La entrada de texto es el control: la caja y todo lo que se escribe en ella. El campo de texto no dibuja nada propio y no tiene ningún token: cada propiedad que tiene es una propiedad de uno de los dos, que recibe sin cambios.

Es un bloque tan ancho como el lugar en el que se pone, y su caja lo llena. No tiene ancho propio: para un campo más estrecho, dale un lugar más estrecho.

Área de pruebas

textemailpasswordnumbersearchtelurlcodedatetimedate-time
Cada control fija una propiedad del componente en vivo, y el código cambia con él. La dirección de la página guarda lo que fijes, así que un enlace la abre tal como la dejaste. El código es para la web. Para las demás plataformas, consulta «Correspondencia de nombres por plataforma».

Uso

<form>
  <tanrei-text-field name="email" label="Correo electrónico" type="email" autocomplete="email" required required-text="Obligatorio"
    supporting-text="Solo lo usamos para iniciar tu sesión."></tanrei-text-field>
  <tanrei-text-field name="company" label="Empresa" optional optional-text="Opcional"></tanrei-text-field>
  <!-- Sigue a su texto de 3 a 8 líneas y después se desplaza. -->
  <tanrei-text-field name="message" label="Mensaje" multiline min-rows="3" max-rows="8"></tanrei-text-field>
  <!-- Su tamaño se cambia a mano, con un tirador. -->
  <tanrei-text-field name="notes" label="Notas" multiline resize="manual" resize-label="Cambiar el tamaño de las notas"></tanrei-text-field>
</form>

<!-- La caja sola, en una barra de herramientas: una entrada de texto, que recibe su nombre de su propio label. Importar el campo de texto la define. -->
<tanrei-text-input label="Buscar" type="search" placeholder="Buscar componentes">
  <span slot="leading-icon">search</span>
</tanrei-text-input>

<!-- Código: de izquierda a derecha y en el tipo de letra de código en cualquier dirección de página, nunca corregido ni revisado por el corrector ortográfico. -->
<tanrei-text-field label="Patrón" type="code" value="tanrei.comp.button.*.container.color"></tanrei-text-field>
<tanrei-text-field label="Cuerpo del webhook" type="code" multiline min-rows="4" supporting-text="JSON"></tanrei-text-field>
<!-- Sin continuar en otra línea: cada línea del código se queda en una sola línea, y una línea larga se desplaza dentro del campo. -->
<tanrei-text-field label="Filas" type="code" multiline no-wrap></tanrei-text-field>

<!-- Una fecha que se introduce unidad por unidad en el orden de la configuración regional, guardada como 2026-09-27, con un botón de selector. -->
<tanrei-text-field id="start" label="Fecha de inicio" type="date" min="2026-01-01" disabled-dates="2026-05-01 2026-12-25"
  invalid-text="Completa la fecha." unavailable-text="Elige un día laborable de 2026 o posterior."
  picker picker-label="Elegir fecha de inicio" segment-empty-text="vacío"></tanrei-text-field>
<tanrei-date-time-picker id="start-picker" presentation="docked" anchor="start" label="Fecha de inicio"></tanrei-date-time-picker>

<script type="module">
  import '@tanrei/web/components/text-field';
  const email = document.querySelector('[name="email"]');
  email.addEventListener('input', () => draft(email.value)); // cada edición
  email.addEventListener('change', () => save(email.value)); // el foco salió o se pulsó Enter, con un valor distinto
  // La validación es tuya: el campo nunca define error por sí mismo.
  email.error = submitted && !isValid(email.value);
  email.errorText = 'Introduce una dirección de correo completa.';

  // El campo pide; el producto presenta el selector y escribe el valor de vuelta.
  const start = document.querySelector('#start');
  const picker = document.querySelector('#start-picker');
  start.addEventListener('pickerrequest', (e) => {
    Object.assign(picker, { value: e.detail.value, min: e.detail.min, max: e.detail.max, disabledDates: start.disabledDates, open: true });
  });
  picker.addEventListener('change', () => (start.value = picker.value));
  picker.addEventListener('close', () => (picker.open = false));
</script>
import { TextField } from '@tanrei/react';

<TextField
  label="Correo electrónico"
  type="email"
  autocomplete="email"
  value={email}
  onInput={(e) => setEmail(e.currentTarget.value)}
  onChange={() => save(email)}
  required
  requiredText="Obligatorio"
  error={submitted && !isValid(email)}
  errorText="Introduce una dirección de correo completa."
/>

<TextField label="Mensaje" multiline minRows={3} maxRows={8} value={message}
  onInput={(e) => setMessage(e.currentTarget.value)} />

// Una fecha: el valor es ISO 8601, o vacío mientras algún segmento esté vacío.
<TextField
  label="Fecha de inicio"
  type="date"
  min="2026-01-01"
  value={start}
  invalidText="Completa la fecha."
  unavailableText="Elige una fecha de 2026 o posterior."
  segmentEmptyText="vacío"
  picker
  pickerLabel="Elegir fecha de inicio"
  onChange={(e) => setStart(e.currentTarget.value)}
  onEntryError={(e) => report(e.detail.reason)}
  onPickerRequest={() => setPickerOpen(true)}
/>
import Tanrei

TanreiTextField("Correo electrónico", text: $email, type: .email,
                supportingText: "Solo lo usamos para iniciar tu sesión.",
                errorText: "Introduce una dirección de correo completa.",
                error: submitted && !isValid(email),
                textContentType: "email", // un nombre de autorrelleno de HTML
                onCommit: save,
                // Pasa la acción aquí: un .onSubmit que lo envuelva se ejecuta antes que onCommit.
                onSubmit: signIn)

// Varias líneas es el eje vertical con un intervalo de límite de líneas.
TanreiTextField("Mensaje", text: $message, axis: .vertical, lineLimit: 3...8)
import androidx.compose.foundation.text.KeyboardActions
import io.github.chnotchy.tanrei.components.TanreiTextField
import io.github.chnotchy.tanrei.components.TanreiTextFieldType

var email by remember { mutableStateOf("") }
TanreiTextField(
    value = email,
    onValueChange = { email = it },
    label = "Correo electrónico",
    type = TanreiTextFieldType.Email,
    contentType = "email", // un nombre de autorrelleno de HTML
    supportingText = "Solo lo usamos para iniciar tu sesión.",
    isError = submitted && !isValid(email),
    errorText = "Introduce una dirección de correo completa.",
    onCommit = { save(it) },
    keyboardActions = KeyboardActions(onDone = { signIn() }),
)

// singleLine es el inverso del multiline de la especificación.
TanreiTextField(value = message, onValueChange = { message = it }, label = "Mensaje", singleLine = false, minLines = 3)
import 'package:tanrei/tanrei.dart';

TanreiTextField(
  controller: email, // o initialValue: '…'
  labelText: 'Correo electrónico',
  type: TanreiTextFieldType.email,
  autofillHints: TanreiTextField.autofillHintsFromHtml('email'),
  helperText: 'Solo lo usamos para iniciar tu sesión.',
  isError: submitted && !isValid(email.text),
  errorText: 'Introduce una dirección de correo completa.',
  onCommit: save,
  onSubmitted: (String value) => signIn(),
);

TanreiTextField(labelText: 'Mensaje', multiline: true, minLines: 3);
import { TextField } from '@tanrei/react-native';

<TextField
  label="Correo electrónico"
  type="email"
  autoComplete="email"
  value={email}
  onChangeText={setEmail}
  supportingText="Solo lo usamos para iniciar tu sesión."
  error={submitted && !isValid(email)}
  errorText="Introduce una dirección de correo completa."
  onEndEditing={save}
  onSubmitEditing={signIn}
/>
<TextField label="Mensaje" multiline minRows={3} value={message} onChangeText={setMessage} />

Un nivel más abajo

El mismo campo, escrito a mano a partir de sus dos miembros, da la misma imagen y es, para la tecnología de apoyo, el mismo cuadro de texto con el mismo nombre, la misma descripción y los mismos estados:

<tanrei-field label="Correo electrónico" required required-text="Obligatorio"
  supporting-text="Solo lo usamos para iniciar tu sesión.">
  <tanrei-text-input name="email" type="email" autocomplete="email"></tanrei-text-input>
</tanrei-field>

El mismo campo escrito a mano: un campo con una entrada de texto dentro

Baja a ese nivel cuando necesites una organización que el campo de texto no ofrezca:

Necesitas Usa
Una etiqueta, la caja, una ayuda, un error y un recuento El campo de texto
Algo tuyo dentro del marco, junto a la caja o debajo de ella Un campo con una entrada de texto y tu propio elemento dentro
La caja sola, bajo una etiqueta que está en otro lugar: un filtro en una barra de herramientas, una celda de una tabla, una fila con su etiqueta al lado La entrada de texto sola, que recibe su nombre de su propio label

Lo que cambia un nivel más abajo es dónde se dice cada cosa. name y value están en la entrada de texto, que es entonces el control con el que trata el formulario, y sus eventos se oyen en ella. label, error, disabled y la obligatoriedad se quedan en el campo, que se los pasa al control: no definas los de la propia entrada.

Hay una cosa que el campo de texto hace y que no hacen el campo y la entrada de texto escritos a mano: mantiene el recuento al día. A mano, con counter definido, da al campo el recuento de la entrada en cada cambio:

field.countText = input.countText;
input.addEventListener('input', () => (field.countText = input.countText));

Especificaciones

Error, deshabilitado, solo lectura, prefijo y sufijo, y contador

Tipos: contraseña, búsqueda, número, teléfono y URL

search

Obligatorio y opcional: los tags y el asterisco

Varias líneas: sigue al texto, cambia de tamaño con un tirador (hacia abajo y en ambos sentidos) y fijo

Código: un patrón en una línea, JSON en varias líneas y líneas que no continúan en otra fila

Código en una página de derecha a izquierda: la etiqueta y la ayuda siguen a la página, el código empieza a la izquierda

Una fecha, una hora, y una fecha y hora, en segmentos. Tab, las teclas de flecha y los dígitos los rellenan

Filled y outlined, las variantes de los preajustes de Material

Con m3-like

Qué aporta cada miembro

Aspecto Del campo De la entrada de texto
Propiedades label, labelHidden, supportingText, errorText, error, disabled, required, optional, requiredMark, requiredText, optionalText Todas las demás: variant, size, type, value, placeholder, readOnly, las líneas y el cambio de tamaño, wrap, maxLength, counter, el prefijo y el sufijo, autocomplete, y todo lo de una fecha o una hora
Eventos — input, change, action, pickerRequest, entryError
Slots label-icon leading-icon, trailing-icon
Tokens comp.field.* comp.input-box.* para la caja, que leen todas las cajas de entrada; comp.text-input.* para lo que solo dibuja una entrada de texto

La entrada de texto tiene un label, un labelHidden, un error y un disabled propios. No son los que define el campo de texto: su label es el del campo, que da nombre a la entrada y que, en un campo filled u outlined, es lo que flota en la caja.

Tokens

El campo de texto no tiene ningún token propio. Su caja lee los tokens de la entrada de texto, y sus filas —la etiqueta, la marca, la ayuda, el error y el recuento— leen los tokens del campo, allí donde estén definidos. La tabla siguiente enumera los del campo. Para cambiar una sola instancia, define en ella el token de un miembro:

<tanrei-text-field label="Correo electrónico"
  style="--tanrei-comp-field-label-gap: 12px"></tanrei-text-field>

Anatomía

Anatomía

Dibujado sobre el fixture outlined-empty, tal como lo dibuja el paquete web.
Parte Descripción
1 field The Field: the label row with its glyph and its requirement mark, and the supporting row with the help, the error text and the count the text field gives it (TXF-67). In a look whose input floats the label it draws no label row.
2 text-input The text input, as the Field's one control: the box and everything typed in it, the icons, the prefix and the suffix, the segments of a date, the picker button, the resize handle, and the label that floats in the box in the looks that float one.

Propiedades

Propiedad Tipo Valor predeterminado Descripción
variant stacked | filled | outlined "stacked" Stacked is a filled box that shows focus and error with a line inside its edge and draws no label: the label of the Field that frames it stands above it. Filled and outlined float the label inside the box, marked by a tinted box and a bottom line, or by a border. Use one style per form. A design system may leave some out (the Tanrei system ships stacked only) or add values. — Text input
size small | medium | large "medium" Minimum height of a single-line input's container: stacked 32 / 40 / 56, as tall as a Button of the same size, so that an input and a Button side by side in one row stand as tall as each other; filled and outlined 40 / 48 / 56, which hold the label that floats inside them. Medium and large are for forms; small is for an input in an app bar, a toolbar or a dense row of controls, beside a small select or button. The hit area always meets the minimum target. — Text input
type text | email | password | number | search | tel | url | code | date | time | date-time "text" What the value is: chooses the keyboard, autocorrection, obscured entry and semantics. code is text written for a machine rather than for a reader — a snippet of configuration, a pattern, an identifier, a query, a key: a left-to-right run in the code face that the platform does not correct, capitalise, check for spelling or complete, on one line or, with multiline, on many. date, time and date-time are entered segment by segment in the locale's numeric form and held as ISO 8601. The value is a string for every type. — Text input
value string "" The text in the field; for date, time and date-time, the ISO 8601 form of what its segments give (2026-09-27, 14:30, 2026-09-27T14:30), or empty while a segment is empty or the value is not available. — Text input
label string "" Names the control, visibly and to assistive technology. Required, unless the control names itself (a checkbox or a switch with its own label): then leave it empty and the field adds only help and an error. — Field Names the text input. In a filled or outlined look the input draws it, floating in its box, and the Field draws no label row (FLD-25, TXI-13).
labelHidden boolean false Does not draw the label, which stays the accessible name. For a control whose visible label is elsewhere (a table column, a toolbar). — Field Hides the label wherever it would be drawn: the Field's row, or the input's floating label (FLD-25).
placeholder string "" A hint shown while the value is empty and the label is not in the input line (above, floated or hidden). Never a replacement for label. In a code field it is an example of the code and is drawn as code (TXI-53, TXI-54); a hint in words belongs in the supportingText of its Field. Ignored by a date, time or date-time field, whose empty segments each show their own. — Text input
supportingText string "" Help shown below the control and given to assistive technology as the control's description. While the field is in error it gives way to errorText, unless the design system keeps both (comp.field.error-text.placement append). — Field
errorText string "" Shown while error is true, in supportingText's place — or below it, which then stays, where the design system's comp.field.error-text.placement is append: what is wrong and how to put it right, in words. — Field
error boolean false Puts the field in the error condition: the error text is drawn, the control is exposed as invalid and, where it has an error condition of its own, drawn in it. What a value means is the product's to validate; the field never sets this itself. — Field The Field puts its text input in the input's own error condition (FLD-8, TXI-11).
disabled boolean false Disables the control and draws the frame as disabled. Disable a framed control here, not on the control, so that its label follows. — Field The Field disables its text input (FLD-14, TXI-5); the text field is then left out of its form (TXF-63).
readOnly boolean false The value can be focused, selected and copied, but not changed. — Text input
required boolean false What the form asks of the control: true exposes it as required and draws the required mark beside the label. It never validates: a missing answer is the product's to report with error. — Field The Field exposes its text input as required (FLD-10, TXI-23).
optional boolean false Draws the optional tag after the label and adds optionalText to the control's description, because assistive technology has no state for it. Ignored while required is true: a control is never both. — Field
requiredMark auto | tag | asterisk | none "auto" How this control shows that it is required: tag is a small filled Tag with requiredText, asterisk is "*" after the label, none draws nothing and keeps the semantics. Auto takes comp.field.requirement.mark, which follows sys.behavior.requirement-mark, the system's one answer. Ignored unless required is true. — Field
requiredText string "" The text of the required tag, in the product's language ("Required", "必須"). The product's: Tanrei has no word for it. Empty reads the product's words; with neither, FLD-24 says what is drawn. — Field
optionalText string "" The text of the optional tag, in the product's language ("Optional", "任意"); also read to assistive technology as part of the description. The product's: Tanrei has no word for it. Empty reads the product's words. — Field
multiline boolean false Accepts line breaks and shows several lines, sized as resize says. Ignored for password, date, time and date-time. — Text input
minRows number 2 The fewest lines a multi-line field shows: the height of an empty auto-resized field, the starting and smallest height of a manually resized one, and the height of a fixed one. — Text input
maxRows number 0 The most lines an auto-resized field grows to before it scrolls, and the tallest a manually resized one can be made; 0 is no limit. Ignored while resize is fixed. — Text input
resize auto | manual | fixed "auto" How a multi-line field gets its height. auto: it follows the number of lines between minRows and maxRows, with an animated change, and has no handle. manual: it starts at minRows lines and the person resizes it with the handle in its bottom end corner. fixed: it stays at minRows lines, with no handle. Ignored unless multiline. — Text input
resizeAxis vertical | both "vertical" What the person can resize by hand: the height only, or the height and the width. Ignored unless resize is manual. — Text input
resizeLabel string "" The accessible name of the resize handle, in the product's language ("Resize"). The product's: Tanrei has no word for it. Empty reads the product's words. Required while the handle is shown. — Text input
wrap boolean true Whether a multi-line code field continues a line that does not fit on following rows (true), or keeps every line of the code on one row and scrolls sideways inside its container (false) — for code whose lines are read as rows: a table of values, a log, a file in which a line break means something. The value is the same either way. Ignored unless type is code and multiline is true: prose always wraps, and a single line always scrolls in its line. — Text input
maxLength number 0 The most user-perceived characters the user can enter; 0 is no limit. Ignored for date, time and date-time. — Text input
counter boolean false Keeps the character count (and maxLength, when set): part of the input's description and announced when typing pauses (TXI-19). The input draws none: a text field gives the count to its Field, which draws it at the end of its supporting row, and a product that frames the input by hand gives it to the Field's countText. — Text input The input keeps the count, the text field gives it to its Field, and the Field draws it (TXI-19, TXF-67, FLD-27).
counterText string "" The count said to assistive technology while counter is true and maxLength is greater than 0: the whole sentence in the product's language with three places the input fills — {count} with the characters entered, {limit} with maxLength and {remaining} with how many more can be entered ("{remaining} characters left", "{limit}文字中{count}文字"). Empty reads the product's words; with neither, the count is said as the digits it is drawn in ("12/40"). A sentence that is right for every number, or a prop set per count where the language needs another form for one. — Text input
counterNoLimitText string "" The count said to assistive technology while counter is true and maxLength is 0: the whole sentence with one place, {count}, filled with the characters entered ("{count} characters", "{count}文字"). Empty reads the product's words; with neither, the count is said as its digits. — Text input
prefixText string "" Fixed text before the value, not part of it. In a code field it is code: drawn in the code face at the left of the value in every layout direction (TXI-53). — Text input
suffixText string "" Fixed text after the value, not part of it. In a code field it is code: drawn in the code face at the right of the value in every layout direction (TXI-53). — Text input
autocomplete string "" The autofill hint, as an HTML autofill field name (email, current-password, new-password, one-time-code, tel, postal-code, …); each platform maps it to its own content type. A code field left without one asks the platform to offer no remembered entry (TXI-55). — Text input
locale string "" A BCP 47 language tag ("en-US", "ja-JP") for how a date, time or date-time field shows and reads its value: the order of the year, month and day segments, the separators, the clock, the digits and the names of the units. Empty uses the platform's current locale. The calendar is the Gregorian calendar in every locale. — Text input
min string "" The earliest value a date, time or date-time field accepts from the person, in its ISO 8601 form; empty for no limit. — Text input
max string "" The latest value a date, time or date-time field accepts from the person, in its ISO 8601 form; empty for no limit. — Text input
disabledDates strings Dates inside min and max that a date or date-time field does not accept from the person, as ISO 8601 calendar dates — the same list the product gives its DateTimePicker. Ignored by a time field. — Text input
invalidText string "" The words for a date, time or date-time input committed with some segments filled and others empty: given to the Field that frames it, which shows them as its error text (TXI-30). — Text input Shown by the Field, in its supporting row (FLD-28).
unavailableText string "" The words for a date, time or date-time input committed with a value before min, after max or, for a date, listed in disabledDates: given to the Field that frames it, which shows them as its error text (TXI-30). — Text input Shown by the Field, in its supporting row (FLD-28).
segmentEmptyText string "" What assistive technology reads as the value of a date or time segment that holds nothing yet, in the product's language ("Empty"). The product's: Tanrei has no word for it. Empty reads the product's words; with neither, an empty segment has no value text. — Text input
picker boolean false Shows the picker button in a date, time or date-time field. The field presents no picker itself: it emits pickerRequest, and the product presents a DateTimePicker in the matching mode and sets value to what was picked. — Text input
pickerLabel string "" The accessible name of the picker button ("Choose date"). Required while picker is shown. — Text input

Slots

Slot Descripción
leading-icon An icon at the start of the input. — Text input
trailing-icon An icon at the end of the input, or the product's own icon-only Button (clear, reveal password). A date or time field's picker button comes after it. — Text input
label-icon A glyph before the label. — Field

Eventos

Evento Descripción
input The user changed the value; carries the new value. Emitted for every change, not when the product sets value. A date, time or date-time field emits it when its value changes — when its last segment is filled, a filled field is edited, or it is emptied — not for a segment that leaves the value empty. — Text input
change The user committed a changed value (focus left the field, or the action key was pressed in a single-line field); carries the value. — Text input
action The user pressed the keyboard's action key (Enter, Return, Go, Search, Done) in a single-line field. — Text input
pickerRequest The user activated the picker button of a date, time or date-time field; carries the value, type, min and max. The product presents the picker and sets value to the picked value. — Text input
entryError The user committed a date, time or date-time field that is half-filled or whose value is not available; carries the reason (invalid: some segments are empty; unavailable: before min, after max or a listed date) and the text of the row of segments as drawn. The entry error itself is shown by the Field that frames the input (TXI-30). — Text input
resizeEnd The person finished changing the size of a field resized by hand: a drag of its handle ended, or a key or an activation of the handle changed the size (TXI-69). Carries lines, the number of lines the input shows, and width, the field's width in pixels WHILE resizeAxis is both (null otherwise). Not emitted when a change of resize, resizeAxis, minRows or maxRows gives the size back. — Text input

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
TXF-62 THE text field SHALL be a Field that frames one text input, and nothing else. It SHALL give label, labelHidden, supportingText, errorText, error, disabled, required, optional, requiredMark, requiredText and optionalText to its Field and every other prop to its text input, each unchanged; SHALL hold the label-icon slot for its Field and the leading-icon and trailing-icon slots for its text input; and SHALL emit its text input's events as its own, each once. THE text field SHALL be as wide as the place it stands in, and its text input SHALL fill it: it is a block with no width of its own, as its Field is (FLD-1), around a control that fills the width it is given (TXI-63). It SHALL draw no part of its own, have no token of its own and hold no state of its own but the count it carries from one member to the other (TXF-67): what it shows, how it behaves and what it exposes to assistive technology SHALL be exactly what that Field and that text input do when a product places the one in the other (FLD-1 to FLD-28; TXI-1 to TXI-63), with the Field given the input's count — the label row and its requirement mark (FLD-2 to FLD-6), or the label that floats in the box with the Field's row left out (FLD-25, TXI-13, TXI-50); the supporting row, the error and the count (FLD-7 to FLD-9, FLD-26, FLD-27, TXI-19, TXF-67); the name, the description and the states (FLD-10, FLD-11, FLD-14, TXI-23); and a date's entry error shown in the Field's row (FLD-28, TXI-30).
TXF-63 WHERE the platform has forms (the web) THE text field SHALL be the one control the form sees: it SHALL take name, submit its text input's value, reset to the value it was first given, restore it on navigation, report to the form's constraint validation exactly what its text input would report there (TXI-23, TXI-30), and be left out WHILE disabled is true or a disabled group of the form holds it; its text input and its Field SHALL take no part in the form themselves. WHEN the action key asks for the form's submission (TXI-3) the form asked SHALL be the text field's own.
TXF-64 WHEN the text field is given focus — by the product, by a press on any part of it that FLD-12 or TXI-8 gives to the input, or by a form that reports its validity — THE text field SHALL pass the focus to its text input (in a date, time or date-time field, to the segment TXI-43 names) and SHALL add no stop to the focus order: the stops inside it are its text input's, in that input's order (an interactive slot element, the picker button, the resize handle). WHILE focus is anywhere inside it THE text field SHALL count as focused for its Field (FLD-13).
TXF-65 IF the text field is placed in a Field THE text field SHALL in debug builds report that it is a field already and that the bare control is the text input, and both SHALL still render (FLD-15). WHILE it stands in a field group THE text field SHALL follow that group's disabled, through its own Field, and take nothing else from the group (FGR-20).
TXF-66 THE text field SHALL have no words of its own and SHALL read none: requiredText and optionalText are read by its Field (FLD-24), resizeLabel and segmentEmptyText by its text input (TXI-52), each from the instance's prop and then from the product's words.
TXF-67 WHILE counter is true THE text field SHALL give its Field, as its count text (FLD-27), the count its text input keeps (TXI-19), as the input writes it, and SHALL give the new one in the same frame in which the value changes — by typing, by a paste, because the product set value or maxLength — without a motion and without an announcement of its own: the input describes and announces its count itself (TXI-19) and the Field keeps the drawn text from assistive technology (FLD-27). WHILE counter is false THE text field SHALL give its Field no count text. THE text field SHALL NOT count, format or write a digit itself.
TXF-68 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 text field 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 the element that carries its role — an id reference by the elements it names in the host's tree or a tree around it, an error message as part of the description while the text field is invalid — except those the text field owns (aria-label, aria-labelledby, aria-disabled), which it SHALL move and not expose: its name is label (TXF-62). 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 text field SHALL take it off that element. WHEN the product sets an aria- attribute the text field owns THE text field SHALL report it in debug builds.

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-text-field TanreiTextField TanreiTextField TanreiTextField TextField
variant · Propiedad variant variant variant variant variant
size · Propiedad size size size size size
type · Propiedad type type type type type
value · Propiedad value text value controller value
label · Propiedad label label label labelText label
labelHidden · Propiedad labelHidden labelsHidden labelHidden labelHidden labelHidden
placeholder · Propiedad placeholder prompt placeholder hintText placeholder
supportingText · Propiedad supportingText supportingText supportingText helperText supportingText
errorText · Propiedad errorText errorText errorText errorText errorText
error · Propiedad error error isError isError error
disabled · Propiedad disabled disabled enabled enabled disabled
readOnly · Propiedad readOnly readOnly readOnly readOnly readOnly
required · Propiedad required isRequired required required required
optional · Propiedad optional isOptional optional optional optional
requiredMark · Propiedad requiredMark requiredMark requiredMark requiredMark requiredMark
requiredText · Propiedad requiredText requiredText requiredText requiredText requiredText
optionalText · Propiedad optionalText optionalText optionalText optionalText optionalText
multiline · Propiedad multiline axis singleLine multiline multiline
minRows · Propiedad minRows lineLimit minLines minLines minRows
maxRows · Propiedad maxRows lineLimit maxLines maxLines maxRows
resize · Propiedad resize resize resize resize resize
resizeAxis · Propiedad resizeAxis resizeAxis resizeAxis resizeAxis resizeAxis
resizeLabel · Propiedad resizeLabel resizeLabel resizeContentDescription resizeSemanticLabel resizeAccessibilityLabel
wrap · Propiedad noWrap wrap softWrap softWrap wrap
maxLength · Propiedad maxLength maxLength maxLength maxLength maxLength
counter · Propiedad counter counter counter showCounter counter
counterText · Propiedad counterText counterText counterText counterSemanticText counterAccessibilityText
counterNoLimitText · Propiedad counterNoLimitText counterNoLimitText counterNoLimitText counterNoLimitSemanticText counterNoLimitAccessibilityText
prefixText · Propiedad prefixText prefix prefix prefixText prefix
suffixText · Propiedad suffixText suffix suffix suffixText suffix
autocomplete · Propiedad autocomplete textContentType contentType autofillHints autoComplete
locale · Propiedad locale locale locale locale locale
min · Propiedad min min min min min
max · Propiedad max max max max max
disabledDates · Propiedad disabledDates disabledDates disabledDates disabledDates disabledDates
invalidText · Propiedad invalidText invalidText invalidText invalidText invalidText
unavailableText · Propiedad unavailableText unavailableText unavailableText unavailableText unavailableText
segmentEmptyText · Propiedad segmentEmptyText segmentEmptyText segmentEmptyText segmentEmptyText segmentEmptyText
picker · Propiedad picker onPickerRequest onPickerRequest onPickerRequest onPickerRequest
pickerLabel · Propiedad pickerLabel pickerLabel pickerContentDescription pickerSemanticLabel pickerAccessibilityLabel
input · Evento input text onValueChange onChanged onChangeText
change · Evento change onCommit onCommit onCommit onEndEditing
action · Evento action onSubmit keyboardActions onSubmitted onSubmitEditing
pickerRequest · Evento pickerrequest onPickerRequest onPickerRequest onPickerRequest onPickerRequest
entryError · Evento entryerror onEntryError onEntryError onEntryError onEntryError
resizeEnd · Evento resizeend onResizeEnd onResizeEnd onResizeEnd onResizeEnd
Notas The tag is tanrei-text-field, the class TanreiTextField, the React name TextField. Members: <tanrei-field> holding one <tanrei-text-input> in its default slot; the product places none. The host is display: block, as wide as its place, and the input fills it (TXF-62). Value member: tanrei-text-input. The host is the form's element — name, the value and its state, validity anchored on the input, reset to the value attribute, restore, form, a disabled fieldset — and the input inside has no name. Props, set as properties on the member each is from. On the Field: label, labelHidden, supportingText, errorText, error, disabled, required, optional, requiredMark, requiredText, optionalText. On the text input: variant, size, type, value, placeholder, readOnly, multiline, minRows, maxRows, resize, resizeAxis, resizeLabel, noWrap (the inverse of wrap, attribute no-wrap), maxLength, counter, prefixText, suffixText, autocomplete, locale, min, max, disabledDates, invalidText, unavailableText, segmentEmptyText, picker, pickerLabel. Attributes are the members' own: kebab-case, except readonly, maxlength, autocomplete, min and max. Props of one name on both members — label, labelHidden, error, disabled — are the Field's; the input's are never set by the element and reach the input through the connection. Events: input, change, action, pickerrequest, entryerror are the text input's own composed events and leave by themselves, with the host as their target and value already new; action stays cancelable. None is stopped and none is copied. Slots: label-icon is passed to the Field, leading-icon and trailing-icon to the text input, each by a slot element of the same name rendered only while the host has a child for it; the product's own Button in trailing-icon stays the product's element. Parts: the member hosts are field and text-input. Exported from the Field: label, label-icon, requirement-label, supporting-text, counter. Exported from the text input: container, outline, active-indicator, label, requirement-label, input, segment, prefix, suffix, leading-icon, trailing-icon, picker-button, resize-handle. Two names collide, label and requirement-label. Each is exported with its member's name before it, always (field-label, text-input-label, field-requirement-label, text-input-requirement-label), and under the bare name from both members as well, because the two are one thing to a person and are never drawn at once: FLD-25 is the sentence that holds it — while its control draws the label itself the Field draws no label row and no requirement tag, and a stacked input draws neither (TXI-13, TXI-50). So tanrei-text-field::part(label) keeps meaning the drawn label. Focus: the shadow root does not delegate. focus() and blur() call the text input's; a press on the label row — the label, its glyph, the requirement mark — focuses the input by FLD-12, the Field's own sentence (the Field calls focus() on its control, which stands beside it in the same tree); a press on the box, and on a label that floats in it, by TXI-8; and a press on the supporting row — the help, the error text, the count — or on the gap between a row and the box does nothing (FLD-12). The connection is the Field's with its control, in both directions (FLD-25, FLD-26, FLD-28, TXI-62); the element takes no part in it. A member's prop it sets itself (fills): the Field's countText, from the text input's read-only countText after each of the input's updates, in the same task (TXF-67). Parts and tokens of its own: none. The element writes no custom property: --tanrei-comp-field-*, --tanrei-comp-input-box-* and --tanrei-comp-text-input-* reach the members by inheritance, and one text field is set apart by setting any of them on the element. What its twin cannot do that it does: keep the Field's count text equal to the input's count as the person types (TXF-67); nothing else. The twin: <tanrei-field label="Email" supporting-text="We never share your address." required><tanrei-text-input name="email" type="email" autocomplete="email"></tanrei-text-input></tanrei-field>. Its Field draws the help and the error text together (FLD-7, FLD-31), and the five fixtures *-supporting-error* hold the pair to its twin. Lagging: this platform draws the text field as one view that draws its own frame, written against the token group comp.text-field, which the tokens do not have. It owes, first, its sources moved to the generated names of comp.input-box, comp.text-input and comp.field: they do not compile until then. Then the split: the text input as a view of its own, and the text field as the Field around it. Its names and its props stay. What it does today: text: Binding<String> (as TextField); every edit writes the binding, which is the input event. password draws a SecureField; multiline is TextField(axis: .vertical) with .lineLimit(minRows...maxRows) — not TextEditor, which has no prompt and does not grow. labelHidden follows the .labelsHidden() environment; disabled follows .disabled(_:); action is the onSubmit: parameter, called after the commit (TXI-3); an enclosing .onSubmit modifier still fires, but before the commit, because SwiftUI runs the outer handler first. onCommit is Tanrei's own parameter (SwiftUI deprecated its own), called when focus leaves with a changed value. type maps to .keyboardType, .textInputAutocapitalization, .autocorrectionDisabled and .submitLabel; autocomplete maps HTML names to UITextContentType. locale follows the \.locale environment when not given. The picker button is shown when an onPickerRequest: closure is given (a nil closure is picker false); the product presents the picker and writes the binding. Not built on this platform yet: the optional flag (optional) beside the required flag; the resize modes and the handle (TXI-37–TXI-41, TXI-69), the segmented date and time row (TXI-42–TXI-47) and the requirement label (FLD-4, FLD-5, TXI-50). The platform proposes its own idiom for the segments when it catches up — each unit focusable and adjustable on its own, with the same value and events. Not built on this platform yet: the words props have no defaults, and the product's words are read from the \.tanreiWords environment value. Not built on this platform yet, for type code: .autocorrectionDisabled(), .textInputAutocapitalization(.never), .keyboardType(.asciiCapable), a monospaced design of the input's size, and .environment(\.layoutDirection, .leftToRight) on the input row alone; smart quotes, smart dashes and smart insert and delete are traits of the UIKit and AppKit text view (smartQuotesType, smartDashesType, smartInsertDeleteType, isAutomaticQuoteSubstitutionEnabled), so a code field is drawn on that view where SwiftUI's TextField gives no access to them; wrap: false needs that view too (a text container that does not track the view's width, in a scroll view), because TextField(axis: .vertical) always wraps. Not built on this platform yet: the count said as the product's sentence (counterText, counterNoLimitText, TXI-19); today the digits are said. Not built on this platform yet: comp.field.error-text.placement — the error text takes the help's place under every system, which is replace, the default; append, which keeps the help and draws the error text below it, is not drawn (FLD-7, FLD-31). Not built on this platform yet: size small (40), and in a right-to-left layout the value of an always left-to-right type beside its prefix (TXI-67). Lagging: this platform draws the text field as one view that draws its own frame, written against the token group comp.text-field, which the tokens do not have. It owes, first, its sources moved to the generated names of comp.input-box, comp.text-input and comp.field: they do not compile until then. Then the split: the text input as a view of its own, and the text field as the Field around it. Its names and its props stay. What it does today: Compose idiom (as TextField): value / onValueChange, with a TextFieldValue overload for products that manage selection and composition themselves; enabled and singleLine are inverse flags; isError, readOnly, minLines, maxLines, prefix and suffix keep Compose's names. Built on BasicTextField. type maps to KeyboardOptions (keyboard type, capitalization, autocorrect, IME action) and, for password, PasswordVisualTransformation; autocomplete maps to ContentType semantics. onCommit is Tanrei's own callback, called when focus leaves with a changed value or the IME action commits. locale defaults to the current configuration's locale. The picker button is shown when onPickerRequest is not null (null is picker false); pickerContentDescription follows Compose's naming for an icon's accessible name. Not built on this platform yet: the optional flag (optional) beside the required flag; the resize modes and the handle (TXI-37–TXI-41, TXI-69), the segmented date and time row (TXI-42–TXI-47) and the requirement label (FLD-4, FLD-5, TXI-50). The platform proposes its own idiom for the segments when it catches up — each unit focusable and adjustable on its own, with the same value and events. Not built on this platform yet: the words props have no defaults, and the product's words are read from LocalTanreiWords. Not built on this platform yet, for type code: KeyboardOptions(capitalization = KeyboardCapitalization.None, autoCorrectEnabled = false, keyboardType = KeyboardType.Ascii), TextStyle(textDirection = TextDirection.Ltr, textAlign = TextAlign.Left, fontFamily = …, fontFeatureSettings = "liga 0") on the input row inside CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr); softWrap = false puts the BasicTextField in a horizontalScroll that follows the cursor's rectangle. Not built on this platform yet: the count said as the product's sentence (counterText, counterNoLimitText, TXI-19); today the digits are said. Not built on this platform yet: comp.field.error-text.placement — the error text takes the help's place under every system, which is replace, the default; append, which keeps the help and draws the error text below it, is not drawn (FLD-7, FLD-31). Not built on this platform yet: size small (40), and in a right-to-left layout the value of an always left-to-right type beside its prefix (TXI-67). Lagging: this platform draws the text field as one view that draws its own frame, written against the token group comp.text-field, which the tokens do not have. It owes, first, its sources moved to the generated names of comp.input-box, comp.text-input and comp.field: they do not compile until then. Then the split: the text input as a view of its own, and the text field as the Field around it. Its names and its props stay. What it does today: Flutter idiom (as TextField and InputDecoration): the value lives in a TextEditingController (or an internal one with initialValue); labelText, hintText, helperText, errorText, prefixText, suffixText, minLines, maxLines, maxLength, readOnly, enabled and autofillHints keep Flutter's names, enabled being the inverse flag. isRequired and showCounter avoid Dart's required keyword and Flutter's own counter, which Tanrei replaces (it counts grapheme clusters with characters). maxRows: 0 is maxLines: null. type maps to keyboardType, obscureText, autocorrect, textCapitalization and textInputAction. onCommit is Tanrei's own callback, called when focus leaves with a changed value. locale defaults to Localizations.localeOf(context). The picker button is shown when onPickerRequest is not null (null is picker false). Not built on this platform yet: the optional flag (optional) beside the required flag; the resize modes and the handle (TXI-37–TXI-41, TXI-69), the segmented date and time row (TXI-42–TXI-47) and the requirement label (FLD-4, FLD-5, TXI-50). The platform proposes its own idiom for the segments when it catches up — each unit focusable and adjustable on its own, with the same value and events. Not built on this platform yet: the words props have no defaults, and the product's words are read from the TanreiWords inherited widget, which the app fills from its own localizations. Not built on this platform yet, for type code: autocorrect: false, enableSuggestions: false, textCapitalization: TextCapitalization.none, smartDashesType: SmartDashesType.disabled, smartQuotesType: SmartQuotesType.disabled, spellCheckConfiguration: const SpellCheckConfiguration.disabled(), textDirection: TextDirection.ltr, textAlign: TextAlign.left, a TextStyle with the code family and fontFeatures: [FontFeature.disable('liga')], the input row in a Directionality(textDirection: TextDirection.ltr); softWrap: false is an EditableText of unbounded width in a horizontal Scrollable that keeps the caret in view, because a multi-line TextField always wraps. Not built on this platform yet: helperText stays while the field is in error and errorText is drawn below it (FLD-7, FLD-31), unlike InputDecoration; today the error text takes the help's place. Not built on this platform yet: the count said as the product's sentence (counterText, counterNoLimitText, TXI-19); today the digits are said. Not built on this platform yet: comp.field.error-text.placement (FLD-7, FLD-31), size small (40), and in a right-to-left layout the value of an always left-to-right type beside its prefix (TXI-67). Lagging: this platform draws the text field as one view that draws its own frame, written against the token group comp.text-field, which the tokens do not have. It owes, first, its sources moved to the generated names of comp.input-box, comp.text-input and comp.field: they do not compile until then. Then the split: the text input as a view of its own, and the text field as the Field around it. Its names and its props stay. What it does today: React Native idiom (as TextInput): value / onChangeText, onEndEditing for a commit, onSubmitEditing for the action key; multiline, readOnly, maxLength and autoComplete keep TextInput's names. type maps to keyboardType, secureTextEntry, autoCapitalize, autoCorrect, inputMode and returnKeyType. A controlled value echoed back during a composition must not reset it (TXI-4). React Native gives JavaScript no signal that a composition is in progress, so the component cannot defer a write the product makes mid-composition; echoing the value back is safe. For date, time and date-time, onChangeText receives the value (ISO 8601 or empty), not the text as typed (TXI-29). The picker button is shown when onPickerRequest is given (undefined is picker false). Locale data needs Intl with formatToParts, which Hermes has only in part. Not built on this platform yet: the optional flag (optional) beside the required flag; the resize modes and the handle (TXI-37–TXI-41, TXI-69), the segmented date and time row (TXI-42–TXI-47) and the requirement label (FLD-4, FLD-5, TXI-50). The platform proposes its own idiom for the segments when it catches up — each unit focusable and adjustable on its own, with the same value and events. Not built on this platform yet: the words props have no defaults, and the product's words are read from the TanreiWordsProvider context. Not built on this platform yet, for type code: autoCorrect={false}, autoCapitalize="none", spellCheck={false}, autoComplete="off", smartInsertDelete={false}, keyboardType="ascii-capable" on iOS and "visible-password" on Android only where suggestions cannot be turned off otherwise, style={{ writingDirection: 'ltr', textAlign: 'left', fontFamily: … }}, the input row with direction: 'ltr'. TextInput has no multi-line form that does not wrap: wrap={false} needs a native text view, and until one exists the field wraps and its README says so. Not built on this platform yet: the count said as the product's sentence (counterText, counterNoLimitText, TXI-19); today the digits are said. Not built on this platform yet: comp.field.error-text.placement — the error text takes the help's place under every system, which is replace, the default; append, which keeps the help and draws the error text below it, is not drawn (FLD-7, FLD-31). Not built on this platform yet: size small (40), and in a right-to-left layout the value of an always left-to-right type beside its prefix (TXI-67).

Tokens

Token Alias de Valor resuelto (claro)
--tanrei-comp-field-counter-gap sys.space.space200 16px
--tanrei-comp-field-error-text-gap sys.space.space50 4px
--tanrei-comp-field-error-text-placement — 0
--tanrei-comp-field-label-icon-gap sys.space.space100 8px
--tanrei-comp-field-label-icon-size sys.icon.small 20px
--tanrei-comp-field-label-gap sys.space.space100 8px
--tanrei-comp-field-motion-state-duration sys.motion.role.state.default 250ms
--tanrei-comp-field-motion-state-easing sys.motion.easing.state cubic-bezier(0.2, 0, 0, 1)
--tanrei-comp-field-requirement-asterisk-gap sys.space.space25 2px
--tanrei-comp-field-requirement-gap sys.space.space100 8px
--tanrei-comp-field-requirement-mark sys.behavior.requirement-mark 0
--tanrei-comp-field-standard-counter-color sys.color.on-surface-variant #4b4b4b
--tanrei-comp-field-standard-disabled-counter-color — #1b1b1b · 38%
--tanrei-comp-field-standard-disabled-error-text-color — #1b1b1b · 38%
--tanrei-comp-field-standard-disabled-error-counter-color — #1b1b1b · 38%
--tanrei-comp-field-standard-disabled-error-label-icon-color — #1b1b1b · 38%
--tanrei-comp-field-standard-disabled-error-label-color — #1b1b1b · 38%
--tanrei-comp-field-standard-disabled-error-required-asterisk-color — #1b1b1b · 38%
--tanrei-comp-field-standard-disabled-error-supporting-text-color — #1b1b1b · 38%
--tanrei-comp-field-standard-disabled-error-value-text-color — #1b1b1b · 38%
--tanrei-comp-field-standard-disabled-label-icon-color — #1b1b1b · 38%
--tanrei-comp-field-standard-disabled-label-color — #1b1b1b · 38%
--tanrei-comp-field-standard-disabled-required-asterisk-color — #1b1b1b · 38%
--tanrei-comp-field-standard-disabled-supporting-text-color — #1b1b1b · 38%
--tanrei-comp-field-standard-disabled-value-text-color — #1b1b1b · 38%
--tanrei-comp-field-standard-error-text-color sys.color.error #cd262f
--tanrei-comp-field-standard-error-counter-color sys.color.on-surface-variant #4b4b4b
--tanrei-comp-field-standard-error-label-icon-color sys.color.on-surface-variant #4b4b4b
--tanrei-comp-field-standard-error-label-color sys.color.on-surface #1b1b1b
--tanrei-comp-field-standard-error-required-asterisk-color sys.color.primary #1b1b1b
--tanrei-comp-field-standard-error-supporting-text-color sys.color.on-surface-variant #4b4b4b
--tanrei-comp-field-standard-error-value-text-color sys.color.on-surface-variant #4b4b4b
--tanrei-comp-field-standard-focused-counter-color — #4b4b4b
--tanrei-comp-field-standard-focused-error-text-color — #cd262f
--tanrei-comp-field-standard-focused-error-counter-color — #4b4b4b
--tanrei-comp-field-standard-focused-error-label-icon-color — #4b4b4b
--tanrei-comp-field-standard-focused-error-label-color — #1b1b1b
--tanrei-comp-field-standard-focused-error-required-asterisk-color — #1b1b1b
--tanrei-comp-field-standard-focused-error-supporting-text-color — #4b4b4b
--tanrei-comp-field-standard-focused-error-value-text-color — #4b4b4b
--tanrei-comp-field-standard-focused-label-icon-color — #4b4b4b
--tanrei-comp-field-standard-focused-label-color — #1b1b1b
--tanrei-comp-field-standard-focused-required-asterisk-color — #1b1b1b
--tanrei-comp-field-standard-focused-supporting-text-color — #4b4b4b
--tanrei-comp-field-standard-focused-value-text-color — #4b4b4b
--tanrei-comp-field-standard-label-icon-color sys.color.on-surface-variant #4b4b4b
--tanrei-comp-field-standard-label-color sys.color.on-surface #1b1b1b
--tanrei-comp-field-standard-required-asterisk-color sys.color.primary #1b1b1b
--tanrei-comp-field-standard-supporting-text-color sys.color.on-surface-variant #4b4b4b
--tanrei-comp-field-standard-value-text-color sys.color.on-surface-variant #4b4b4b
--tanrei-comp-field-supporting-text-gap sys.space.space50 4px
--tanrei-comp-field-value-text-gap sys.space.space200 16px
--tanrei-comp-field-label-typescale sys.typescale.label 500 14px/1.4286
--tanrei-comp-field-supporting-text-typescale sys.typescale.label-small 500 12px/1.3333
--tanrei-comp-field-value-text-typescale sys.typescale.label 500 14px/1.4286

Fixtures

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

Generado a partir de specs/text-field.spec.json, tokens/comp/field.tokens.json, design/tokens/

Qué dibuja la web de otra manera

  • El shadow root del elemento contiene un <tanrei-field> con un <tanrei-text-input> dentro, y nada más. Importar el elemento define ambos.
  • El elemento es un bloque que llena su lugar, no una caja en línea tan ancha como el campo de entrada de texto propio del navegador.
  • El elemento está asociado a formularios. Recibe name y form, envía el valor —nada mientras está deshabilitado—, se restablece al valor del atributo value, se restaura al navegar, sigue a un <fieldset> deshabilitado y notifica que falta un valor mientras required está activado y está vacío. Sus dos miembros no añaden ninguna entrada al formulario. Enter en un campo de una sola línea pulsa el botón predeterminado del formulario del elemento; cancela action para impedirlo.
  • input, change, action, pickerrequest y entryerror son los eventos propios de la entrada de texto. Su destino es el elemento, y event.target.value es el nuevo valor en todos los listeners. Los tipos del detalle son los de la entrada: TanreiTextInputActionDetail, TanreiTextInputPickerRequestDetail y TanreiTextInputEntryErrorDetail.
  • Partes: field y text-input son los dos miembros. Sus propias partes tienen aquí los mismos nombres que un nivel más abajo: label-icon, supporting-text, counter; container, outline, active-indicator, input, segment, prefix, suffix, leading-icon, trailing-icon, picker-button, resize-handle. label y requirement-label son las que se dibujan, sea cual sea el miembro que las dibuja; field-label, text-input-label, field-requirement-label y text-input-requirement-label nombran las de un solo miembro.
  • El elemento no puede recibir el foco por sí mismo y no tiene rol: focus() va a la entrada. Una pulsación en la fila de la etiqueta, en la caja o en una etiqueta flotante da el foco a la entrada. Una pulsación en la ayuda, en el texto de error, en el recuento o en el hueco entre una fila y la caja no hace nada.
  • Dale nombre con label —con label-hidden donde la etiqueta no deba dibujarse— y nunca con aria-label, que aquí no nombra nada.
  • Los atributos son los de los propios miembros: en kebab-case, como supporting-text, error-text, min-rows y no-wrap, salvo readonly, maxlength, autocomplete, min y max. No hay atributo required: escribe required.
  • Antes de que el elemento esté definido no tiene tamaño. Reserva su altura.

Pautas

Cuándo usarlo

Usa un campo de texto cuando las personas escriben un valor: un nombre, una dirección de correo electrónico, una búsqueda, un mensaje. Cuando eligen entre un conjunto conocido de valores, usa un control pensado para elegir. Donde solo se quiere la caja, porque la etiqueta está en otro lugar —un filtro en una barra de herramientas, una celda de una tabla—, usa una entrada de texto.

Cómo elegir una variante y un tamaño

Usa una sola variante en todo un formulario.

Variante Se distingue por Dónde
Stacked (predeterminada) La etiqueta encima de una caja teñida y sin borde. El foco dibuja una línea por dentro del borde de la caja, que no mueve nada; un error dibuja una línea delgada en reposo. Todos los sistemas. Es la única variante que incluye el sistema Tanrei.
Filled Una caja teñida y una línea inferior, con la etiqueta flotando dentro Los preajustes de Material y cupertino
Outlined Un borde que se engrosa con el foco, con la etiqueta que flota hasta él Los preajustes de Material y cupertino

La variante predeterminada es stacked en todos los sistemas, incluidos los preajustes. Un producto de Material que quiera la etiqueta flotante de Material define variant como outlined o filled en sus campos. Con el sistema Tanrei, filled y outlined siguen funcionando, con una advertencia en desarrollo.

medium (40) es el campo denso y large (56), el estándar. Usa medium en filtros y ajustes densos, y large en formularios de inicio de sesión y de pago. small (32) es la altura del selector pequeño, para un campo en una barra de aplicación, una barra de herramientas o una fila densa de controles, donde su texto de entrada es de 14. El texto de entrada es de 16 en los otros dos tamaños en el sistema predeterminado. Las alturas son mínimos: el campo crece con un texto más grande, y el área de toque siempre cumple el objetivo mínimo.

Etiquetas y marcadores de posición

  • Todo campo necesita un label. En un campo stacked está encima de la caja, desde su borde de inicio, y nunca se mueve ni cambia de tamaño; una etiqueta larga salta de línea en lugar de cortarse. Un slot label-icon puede poner un glifo delante de ella. En un campo filled u outlined, la etiqueta descansa dentro del campo mientras está vacío y flota cuando el campo tiene el foco o tiene contenido.
  • labelHidden deja de dibujar la etiqueta, pero esta sigue siendo el nombre accesible, y la ayuda y el error siguen debajo de la caja. Donde solo se quiere la caja —un filtro en una barra de herramientas, una celda, una fila cuya etiqueta está al lado—, usa en su lugar una entrada de texto con su propio label.
  • El marcador de posición es una pista, como un valor de ejemplo. Se muestra mientras el campo está vacío y la etiqueta no está en la línea de entrada: siempre en un campo stacked, y solo mientras la etiqueta está flotando u oculta en los demás. Nunca es el nombre.

Obligatorio y opcional

required y optional dicen qué pide el formulario de un campo: required, que hay que responderlo; optional, que se puede dejar vacío. Un campo nunca es las dos cosas: con ambos es obligatorio.

  • Obligatorio expone el campo como obligatorio y dibuja la marca de obligatorio junto a la etiqueta.
  • Opcional dibuja el tag de obligatoriedad en su forma de opcional y añade su texto a la descripción del campo.
  • La marca es, de forma predeterminada, un tag pequeño después de una etiqueta stacked: filled para obligatorio, tonal para opcional. Sus palabras son requiredText y optionalText, y son tuyas: en el campo, o una sola vez para todo el producto con setWords(). Tanrei no incluye ninguna: sin requiredText, un asterisco ocupa el lugar del tag, y sin optionalText no se dibuja ningún tag. No hace más alta la fila de la etiqueta, y salta a una línea propia cuando la etiqueta no le deja sitio.
  • Un asterisco en su lugar. Qué marca dibuja un campo obligatorio es una sola decisión del sistema de diseño para todos los formularios, sys.behavior.requirement-mark: el tag en el sistema predeterminado, un asterisco en los preajustes de Material, nada en cupertino. requiredMark la sustituye para un solo campo (tag, asterisk o none, que conserva la semántica y no dibuja nada). Un campo filled u outlined dibuja el asterisco donde se pide el tag.
  • Opcional en una etiqueta flotante. Un campo filled u outlined no tiene sitio para el tag de opcional junto a una etiqueta que flota: en su lugar dibuja optionalText después de la etiqueta, como una palabra («Empresa Opcional», «会社名 (任意)»), en reposo y flotando con ella. Escribe la palabra como la muestran tus formularios, con paréntesis o sin ellos.
  • No valida nada. El campo nunca define error por un valor que falta. Lo haces tú, con error y errorText.

Marca en un formulario lo que sea menos frecuente: donde la mayoría de los campos son obligatorios, marca los opcionales, y viceversa. Si usas el asterisco —y un campo filled u outlined siempre lo usa para un campo obligatorio—, di una vez en el formulario, cerca de su principio, qué significa («* Obligatorio»): un asterisco es una convención, no una palabra, y no todo el mundo la conoce.

Un campo obligatorio muestra una marca: define requiredMark como none donde no quieras ninguna.

Texto de ayuda y de error

  • supportingText es una línea de ayuda debajo del campo. También se lee como la descripción del campo.
  • La validación es tuya. Cuando un valor sea incorrecto, activa error y escribe errorText: ocupa el lugar del texto de apoyo mientras el campo está en error, de modo que un formulario en error no es más alto que en reposo. Di en él lo que decía la ayuda, donde todavía importe. Un sistema de diseño que mantiene la ayuda a la vista define comp.field.error-text.placement como append: el texto de error se dibuja entonces debajo de la ayuda, y el campo es una línea más alto mientras está en error (consulta el campo).
  • Di cómo corregir el valor, no solo que es incorrecto: «Introduce una dirección de correo completa.», no «No válido».
  • Muestra un error después de que la persona salga del campo o envíe el formulario, no mientras todavía escribe.

El contador

  • maxLength limita lo que una persona puede escribir. Cuenta los caracteres como los ven las personas, de modo que un emoji o una letra acentuada cuentan una vez. Un texto pegado se acorta para que quepa. Un valor que defines tú nunca se acorta.
  • counter muestra el recuento al final de la fila de apoyo, seguido del límite cuando maxLength está definido («12/40»).
  • Muestra el contador solo cuando el límite le importe a la persona, como en un nombre visible o una biografía breve.

Tipos de entrada

type elige el teclado, la autocorrección y la entrada oculta. El valor es una cadena en todos los tipos.

Tipo Teclado y comportamiento
text Un teclado general.
email Un teclado de correo electrónico, sin mayúsculas automáticas ni autocorrección.
password Entrada oculta y segura, sin autocorrección. Siempre de una línea.
number Un teclado numérico con separador decimal. El valor no se analiza, no se redondea ni se valida.
search Un teclado general cuya tecla de acción dice buscar.
tel Un teclado de teléfono.
url Un teclado de URL, sin mayúsculas automáticas ni autocorrección.
code Un teclado general, y no se le hace nada al texto: sin autocorrección, sin mayúsculas automáticas, sin revisión ortográfica y sin caracteres sustituidos. De una línea o, con multiline, de varias. Consulta Código.
date, time, date-time Una fecha, una hora o ambas, que se introducen unidad por unidad en el formato numérico de la configuración regional. Siempre de una línea. Consulta Fechas y horas.

Añade autocomplete con un nombre de autorrelleno de HTML (email, current-password, one-time-code …) para que la plataforma pueda rellenar el campo. Cada plataforma lo asigna a su propio tipo de contenido. Un código corto de longitud conocida que se dibuja en celdas es una entrada de código de un solo uso.

Varias líneas

multiline acepta saltos de línea y muestra varias líneas. resize dice cómo obtiene el campo su altura:

resize Altura Tirador minRows y maxRows
auto (predeterminado) Sigue el número de líneas, con un movimiento breve Ninguno El menor y el mayor número de líneas. Pasado el mayor, se desplaza; 0 es sin límite
manual La que le da la persona. Empieza en minRows En la esquina inferior del borde de fin Lo más bajo y lo más alto que se puede hacer
fixed minRows líneas Ninguno maxRows se ignora
  • Auto conviene a la mayoría de los campos: un comentario, un mensaje, una descripción. Define maxRows donde un texto largo no deba empujar el resto del formulario.
  • Manual conviene a un texto que la persona relee y organiza: notas, una descripción larga, código. resizeAxis es vertical de forma predeterminada; both permite además a la persona cambiar el ancho del campo, dentro de lo que admita su diseño. El tamaño se conserva, y el texto salta de línea y se desplaza dentro de él.
  • Fixed conviene a un formulario cuyo diseño no debe moverse, como un bloque de dirección.
  • El tirador funciona sin arrastrar. Es un tirador de tamaño pequeño en la esquina inferior del borde de fin, que no se ve hasta que un puntero pasa sobre el campo o el campo tiene el foco, y una parada de foco que recibe su nombre de resizeLabel. Las teclas de flecha cambian el tamaño de línea en línea, Re Pág y Av Pág de minRows en minRows líneas, Inicio y Fin van a lo más bajo y a lo más alto, y un clic, Enter o Espacio ajustan la altura al texto, o la devuelven a minRows cuando ya está ajustada. Donde resizeAxis es both, ese mismo clic también hace el campo tan ancho como su lugar, y el siguiente le devuelve el ancho que tenía, de modo que un puntero puede cambiar el ancho sin arrastrar. Su objetivo es el objetivo mínimo, aunque su línea sea pequeña. Cuando la persona ha cambiado el tamaño, el campo emite resizeend con las líneas que muestra (y su ancho, donde cambia de tamaño en las dos direcciones), para que puedas conservar el tamaño que eligió. Un campo deshabilitado no tiene tirador; uno de solo lectura lo conserva, porque leer puede requerir ese espacio.
  • Nada de lo que hay encima del texto se mueve. La primera línea de un campo de varias líneas está donde un campo de una línea dibuja la suya, y sus iconos, su prefijo y su sufijo se centran en esa línea. Todas las líneas siguientes quedan debajo, de modo que la etiqueta y la primera línea no se mueven mientras la altura cambia.

Código

type="code" es para un texto escrito para una máquina y no para un lector: un patrón, un identificador, una clave, una consulta, un fragmento de JSON o de YAML. Es el mismo campo (la misma etiqueta, la misma ayuda, el mismo error, el mismo contador, los mismos tamaños y el mismo comportamiento en un formulario), con una línea de entrada que conserva el código exactamente como se escribe.

  • De izquierda a derecha, en todos los idiomas. El valor, su cursor de texto, el marcador de posición, el prefijo y el sufijo son una sola fila de izquierda a derecha que empieza a la izquierda, también en una página de derecha a izquierda y sea cual sea la primera letra del código: un campo vacío, uno que contiene solo { y uno cuya primera cadena está en árabe se disponen igual. Todo lo demás sigue a la página: la etiqueta, los iconos, el texto de ayuda o de error, el contador y el tirador de cambio de tamaño. Una cadena o un comentario en una escritura de derecha a izquierda se dispone dentro de su línea y no reordena nada a su alrededor.
  • El tipo de letra de código, al tamaño de la entrada. La familia es la del rol de código; el tamaño y el interlineado siguen siendo los de la entrada, de modo que un campo de código es tan alto como el campo de texto que tiene al lado. Todos los espacios se conservan, un carácter de tabulación llega hasta la siguiente posición de tabulación y nunca se unen dos caracteres en una ligadura. Nada se colorea por lo que significa.
  • No se toca. Se pide a la plataforma que no corrija el valor, no le ponga mayúsculas, no revise su ortografía, no lo traduzca ni lo complete, y que no convierta las comillas rectas en tipográficas. Un texto pegado es texto sin formato, carácter por carácter. El valor nunca se recorta, se analiza ni se valida: decir si está bien formado te corresponde a ti, con error y errorText.
  • Una línea o varias. Una línea conviene a un patrón o a una clave. Con multiline, una línea que no cabe continúa de forma predeterminada en las filas siguientes; el valor contiene solo los saltos de línea del código.
  • Líneas que no continúan en otra fila. wrap en false (no-wrap en la web) mantiene cada línea del código en una sola línea del campo, para una tabla de valores, un registro de eventos (log) o un archivo en el que un salto de línea significa algo. Una línea larga se desplaza hacia los lados dentro del campo y no ensancha nada. Solo un campo de código de varias líneas lee wrap: la prosa siempre salta de línea, y una sola línea siempre se desplaza dentro de su línea.
  • Tab mueve el foco. Ninguna tecla cambia de significado: Tab nunca aplica sangría, Enter no añade sangría y ningún paréntesis ni corchete se cierra por ti. Un carácter de tabulación llega al pegar o desde tu producto, y se conserva.
  • No es un editor. No hay colores de sintaxis, ni números de línea, ni plegado, ni marcas de error por línea. Para un código que se muestra y no se escribe, usa un bloque de código; para un editor, incrusta el que haya elegido tu producto.
  • Un marcador de posición es un ejemplo del código, dibujado como código. Una pista con palabras va en supportingText, que es también donde el campo dice qué espera («JSON»).

En un campo de derecha a izquierda, un valor de código empieza a la izquierda, mientras que un valor email, url, tel, number o password va de izquierda a derecha desde el borde de inicio del campo, el derecho. Las demás plataformas todavía no han construido el tipo de código.

Fechas y horas

Un campo date, time o date-time es una fila de segmentos en la línea de entrada, uno por cada unidad: el mes, el día y el año, la hora, el minuto y, en un reloj de 12 horas, el periodo del día. Están en el orden de la configuración regional, con sus separadores. El campo guarda el valor en ISO 8601, sin zona horaria.

Tipo Valor Fila en en-US Fila en ja-JP
date 2026-09-27 09/27/2026 2026/09/27
time 14:30 2:30 PM 14:30
date-time 2026-09-27T14:30 09/27/2026, 2:30 PM 2026/09/27 14:30
  • La configuración regional. locale, o la de la plataforma, establece el orden, los separadores, el reloj y los dígitos. Un segmento vacío muestra su propio marcador de posición («mm», «dd», «yyyy»), de modo que la fila siempre muestra su formato. Cada segmento es tan ancho como el mayor entre su marcador de posición y su valor más ancho, de modo que la fila no se mueve al escribir ni al borrar. Estos tipos ignoran placeholder, prefixText, suffixText, maxLength y multiline.
  • Moverse. Tab visita cada segmento y después el botón de selector. Flecha izquierda y Flecha derecha llevan al segmento de ese lado, en cualquier dirección de diseño: la fila se escribe de izquierda a derecha, como una fecha en dígitos. Pulsar un segmento le da el foco. El segmento con foco se dibuja como texto seleccionado, sin cursor de texto.
  • Avanzar paso a paso. Flecha arriba y Flecha abajo cambian un segmento de uno en uno y dan la vuelta; en un segmento vacío empiezan en la fecha de hoy o en la hora actual. Re Pág y Av Pág dan pasos mayores, e Inicio y Fin van a los extremos del intervalo.
  • Escribir. Un dígito rellena el segmento, y el foco avanza cuando ningún otro dígito podría ampliarlo, o cuando se escribe el separador. Retroceso quita un dígito, y en un segmento vacío vuelve al anterior. Un año necesita cuatro dígitos. No se puede introducir una fecha que no existe: un día posterior al final de un mes recién elegido pasa a ser el último día de ese mes.
  • Pegar. Una fecha o una hora completas pegadas sobre cualquier segmento rellenan la fila. Se leen como tres grupos de dígitos en el orden de la configuración regional, y un primer grupo de cuatro dígitos se lee como el año, de modo que una fecha ISO pegada funciona en todas partes. Copiar y cortar toman la fila entera.
  • El valor está vacío hasta que todos los segmentos están rellenos y el resultado está disponible. input se emite cuando el valor cambia (se rellena el último segmento, se edita una fila rellena o se vacía) y no por un segmento que deja el valor vacío. change se emite cuando el foco sale de los segmentos y del botón de selector del campo, o cuando se pulsa la tecla de acción, con un valor distinto. Moverse entre segmentos no confirma nada.
  • El error de entrada. Un campo que se deja a medio rellenar muestra invalidText. Uno que se deja con un valor anterior a min, posterior a max o incluido en disabledDates muestra unavailableText. Cualquiera de los dos se dibuja como un error y emite entryError con su motivo (invalid o unavailable); la siguiente edición le pone fin. Es el único error que el campo define por sí mismo, y no toca tu propiedad error.
  • Lo que defines tú se muestra tal cual, nunca se valida y no emite nada.

El reloj de un campo es el de su configuración regional: no tiene ajuste de 12 o 24 horas ni paso de minutos, como sí tiene el DateTimePicker.

El botón de selector. Con picker, el campo dibuja al final un Button de solo icono, calendar_month para una fecha y schedule para una hora, que recibe su nombre de pickerLabel. Al activarlo emite pickerRequest con el valor, el tipo, min y max; una fila a medio rellenar envía un valor vacío y no produce ningún error de entrada, porque el selector está a punto de dar un valor completo. El campo no presenta nada por sí mismo: tu producto abre un DateTimePicker en el modo correspondiente, anclado al campo cuando está acoplado, y define el value del campo a partir del change del selector. Da al selector los mismos min, max y disabledDates que al campo. El foco vuelve al botón cuando el selector se cierra. El botón se deshabilita con el campo y no se dibuja mientras este es de solo lectura.

Recomendado

  • Pon en prefixText y suffixText el texto fijo que no forma parte del valor: un signo de moneda, una unidad.
  • Pon una acción de borrar o de mostrar la contraseña en el slot final como tu propio Button de solo icono, con su propio nombre. El botón de selector es la única acción que el campo incorpora, y va después de la tuya.
  • Usa multiline para un texto que pueda ocupar varias líneas. De forma predeterminada crece de minRows a maxRows y después se desplaza.
  • Define required en los campos que pide un formulario y, aun así, di qué falta en errorText cuando se envíe el formulario.
  • Usa type="code" para un valor que lee una máquina (un patrón, una clave, un fragmento de configuración) y di qué debe ser en la etiqueta y en supportingText.

Evita

  • No uses el marcador de posición como etiqueta. Desaparece en cuanto alguien escribe.
  • No uses number para valores que no son cantidades, como un número de tarjeta o un código postal. Usa text con el autocomplete adecuado.
  • No mezcles variantes en un mismo formulario.
  • No pongas un campo de texto dentro de un campo. Ya es un campo; una compilación de depuración lo dice. El control que un campo enmarca es la entrada de texto.
  • No uses un campo text y tu propio análisis para una fecha. Usa date, y con él vienen el orden de la configuración regional, las teclas de los segmentos y el error de entrada.
  • No escribas «(obligatorio)» en la etiqueta además de definir required. La marca ya lo dice, y un lector de pantalla lo oiría dos veces.
  • No dejes que un campo cuyo tamaño se cambia a mano sea la única forma de ver un texto largo. Dale suficientes minRows para que sea útil tal como se abre.
  • No deshabilites un campo solo para mostrar un valor que no puede cambiar. Usa readOnly, para que las personas puedan seguir dándole el foco, seleccionándolo y copiándolo.
  • No pongas un tipo de letra de código a un campo de texto desde fuera, con ::part(input) o con un estilo tuyo, y no añadas dir ni spellcheck al elemento. Usa type="code": el tipo de letra por sí solo deja un campo que tiene el aspecto correcto y sigue corrigiendo lo que se escribe.
  • No uses un campo de código como editor, y no uses uno deshabilitado para mostrar un código largo: un campo deshabilitado no tiene cursor de texto con el que desplazarlo. Usa readOnly, o un bloque de código.

Accesibilidad

Rol
textbox
Etiquetado
The text field adds nothing to what its members expose, and the one thing it coordinates — the drawn count (TXF-67) — is kept from assistive technology, which hears the count from the input: the Field gives the text input its name, its description and its required, invalid and disabled states (FLD-8, FLD-10, FLD-11, FLD-14), and the text input carries them on its own element (TXI-23). Assistive technology meets one text box — or, for a date or a time, one group of spin buttons — named by label, exactly as it meets a Field around a text input written by hand.
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
Every key The text input's (its accessibility block; TXI-3, TXI-41, TXI-43 to TXI-45, TXI-59). The text field handles no key and adds no focus stop (TXF-64).

Notas

  • One level down is the same thing: a Field with a text input in it. Every fixture has that pair as its twin, and the accessibility tree of the two is the same (TXF-62). What the pair by hand does not do by itself is keep the Field's count text equal to the input's count as the person types (TXF-67): the product writes it at each input.
  • On the web the two members stand in the text field's own shadow root, so the form meets the text field and not the input (TXF-63); focus passes through to the input (TXF-64).

Generado a partir de specs/text-field.spec.json, tokens/sys/measure.tokens.json

De qué se encarga el componente

  • El texto se edita en el elemento de texto propio de la plataforma, de modo que los métodos de entrada, el dictado, el autorrelleno, la selección y el portapapeles funcionan como en el resto de la plataforma. Una fecha o una hora son la excepción declarada: su fila de segmentos es propia del campo.
  • Un campo de fecha o de hora es un grupo que recibe su nombre de la etiqueta. Cada segmento es un botón de número (spin button) que recibe su nombre de su unidad y de la etiqueta («mes, Fecha de inicio»), con su intervalo y su valor; uno vacío lee segmentEmptyText.
  • Un campo obligatorio se expone como obligatorio. La marca en sí queda oculta para la tecnología de apoyo, para que no se lea dos veces; el texto de opcional se lee con la descripción del campo.
  • El tirador de cambio de tamaño es una parada de foco que recibe su nombre de resizeLabel, expuesta como un separador cuyo valor es el número de líneas. Las teclas de flecha, Inicio y Fin cambian el tamaño, así que nada depende de un arrastre, y su área de pulsación cumple el objetivo mínimo.
  • La etiqueta es el nombre accesible, se dibuje o esté oculta. El marcador de posición nunca lo es.
  • El texto de apoyo o de error que se muestra y el recuento son la descripción del campo. También lo son el prefijo y el sufijo mientras se muestran, de modo que una unidad o una moneda se leen con el valor.
  • Expone el estado deshabilitado, y los estados no válido, obligatorio y de solo lectura donde la plataforma los tiene. Un error de entrada en un campo de fecha o de hora se expone exactamente igual que error.
  • El botón de selector es un Button que recibe su nombre de pickerLabel, expuesto como algo que abre un diálogo, y una parada de tabulación después del último segmento.
  • Cuando un error aparece o cambia mientras el campo tiene el foco, se anuncia una vez, de forma cortés. El recuento se anuncia tal como se muestra («12/40») cuando la escritura se detiene durante un segundo, nunca en cada pulsación de tecla.
  • Un campo de búsqueda se expone como un cuadro de búsqueda donde la plataforma tiene ese rol.
  • Un campo de código es el mismo cuadro de texto que cualquier otro tipo, de varias líneas con multiline: ningún rol, ninguna descripción de rol y ninguna palabra dice que contiene código, y ninguna parte de su valor se marca como mal escrita. Tab siempre sale de él. Donde sus líneas no continúan en otra fila, el cursor de texto lo desplaza, y el foco se muestra en el contenedor, que no se desplaza.
  • El foco se muestra con el propio borde del campo, venga del teclado o de un puntero: una línea dentro de la caja de un campo stacked, y el borde más grueso y con color de un campo filled u outlined. El área de pulsación cumple el objetivo mínimo.
  • Una pulsación en la etiqueta o en la caja lleva el foco a la entrada y no acciona nada. Una pulsación en la ayuda, en el texto de error o en el recuento no hace nada.
  • El nombre, la descripción y los estados se vinculan exactamente como un campo los vincula a cualquier control que enmarca. El campo escrito a mano, un nivel más abajo, es el mismo cuadro de texto.
  • Las compilaciones de depuración notifican una etiqueta que falta.

Carencias conocidas por plataforma:

  • SwiftUI, Compose, Flutter y React Native conservan el indicador required, que no dibuja ninguna marca, y no tienen modos de cambio de tamaño, ni tirador, ni segmentos.
  • Web: la fila de segmentos se mueve unos pocos píxeles cuando un mes o un minuto reciben su primer dígito; input puede emitirse dos veces donde el último segmento de la configuración regional tiene dos dígitos; en un teclado en pantalla de Android, Retroceso en un segmento vacío no puede volver al anterior; y una fila más ancha que un campo estrecho se desborda en lugar de desplazarse.
  • Un producto no puede vaciar una fila de fecha a medio rellenar definiendo value como la cadena vacía que ya tiene.
  • Web: con el estilo de foco de resplandor, el resplandor de un campo filled se redondea en las esquinas inferiores, que son rectas.
  • Web: la composición con métodos de entrada y la etiqueta con autorrelleno se prueban solo en Chromium.
  • Web: un campo de código de solo lectura cuyas líneas no continúan en otra fila se desplaza desde el teclado como el navegador desplaza cualquier texto que no edita: con el cursor de texto en Firefox, con las teclas de flecha en Chrome, con Opción y las teclas de flecha en Safari. Firefox devuelve un campo así a su borde izquierdo cuando cambia la dirección de la página.
  • SwiftUI, Compose, Flutter y React Native no han construido el tipo de código: allí type no tiene code y el campo no tiene wrap.
  • SwiftUI no tiene estados no válido, obligatorio ni de solo lectura. Se dibujan o se aplican, pero no se anuncian. Un error se oye solo como su texto en la descripción.
  • SwiftUI no puede ver la composición con métodos de entrada, así que maxLength se aplica también al texto que aún se está componiendo, y un valor que defines durante una composición no se retiene.
  • SwiftUI: el texto seleccionado se resalta con el tinte del cursor de texto, no con el color de selección del campo.
  • SwiftUI dibuja el valor de un campo de solo lectura como texto seleccionable, no como un campo de texto.
  • SwiftUI lee .labelsHidden() solo a partir de iOS 18 y macOS 15. En versiones anteriores, la etiqueta se sigue dibujando.
  • React Native no puede ver la composición con métodos de entrada. Un valor que cambias durante una composición, y el límite de maxLength, se aplican de inmediato y pueden poner fin a la composición.
  • React Native no tiene estados no válido, obligatorio ni de solo lectura. Un error se oye solo como su texto en la descripción; obligatorio y solo lectura no se anuncian.
  • React Native: los anuncios, el autorrelleno y el teclado de cada tipo se prueban solo con simulaciones (mocks), todavía no en un dispositivo.
  • React Native en iOS tiene un solo tinte para el cursor de texto y el resaltado de la selección. El campo conserva el color del cursor, así que el resaltado es un tinte de este y no el color de selección del campo.
  • React Native: el resplandor de un campo filled sigue solo sus esquinas superiores, y los colores del marcador de posición y del cursor de texto cambian de golpe en lugar de hacerlo a lo largo del movimiento del estado.
  • Flutter expone un campo de búsqueda como un tipo de entrada de búsqueda, no con el rol de cuadro de búsqueda.
  • Flutter no dibuja controles de selección ni barra de herramientas de selección en Android y otras pantallas táctiles. La pulsación larga y los atajos de teclado siguen seleccionando y copiando; iOS muestra su menú del sistema.
  • Flutter: un elemento interactivo en el slot inicial va antes de la entrada en el orden de foco, no después.
  • Compose no tiene estado obligatorio: en su lugar, el campo lee «Required» como su descripción de estado.
  • Compose: maxLength y el contador cuentan los caracteres como los ven las personas, pero las secuencias de emojis y las banderas no están probadas. Las pruebas se ejecutan en la JVM con Robolectric, cuyas reglas de caracteres no las conocen.
  • Compose: los anuncios del error y del recuento por parte de TalkBack, un método de entrada real y un servicio de autorrelleno real no se han probado en un dispositivo.

Qué debes hacer tú

  • Escribe una etiqueta que nombre el valor, y consérvala aunque la ocultes.
  • Escribe un texto de error que diga cómo corregir el valor, y activa error tú. En SwiftUI y React Native, ese texto es la única forma de que el error se oiga. Para un campo de fecha o de hora, escribe también invalidText y unavailableText, y da segmentEmptyText: sin él, un segmento vacío se lee sin ningún valor.
  • Da al botón de selector su pickerLabel en el idioma de tu producto, y abre el selector desde pickerRequest.
  • Define required u optional y da requiredText y optionalText: en el campo, o una sola vez para todo el producto con setWords({ requiredText, optionalText }), como también se pueden dar resizeLabel y segmentEmptyText. En la web, Tanrei no incluye textos propios; si falta uno, se notifica en desarrollo. Consulta Los textos del producto. Hasta que SwiftUI, Compose, Flutter y React Native se pongan al día, sus campos no dibujan ninguna marca, y SwiftUI y React Native no anuncian el estado obligatorio: allí, di «obligatorio» en la etiqueta.
  • Da nombre al tirador de cambio de tamaño con resizeLabel. Sin él, el tirador se dibuja y funciona, y no tiene nombre.
  • Pon una unidad o una moneda en prefixText o suffixText, no en el valor, para que se lea con el valor y no haya que escribirla.
  • Para un campo de código, di qué debe ser el código en label y supportingText («Cuerpo del webhook», «JSON») y di qué tiene de incorrecto en errorText: el campo no conoce el lenguaje.
  • Da a un botón de icono final su propio nombre en el idioma de tu producto.
  • En Compose, las palabras «Invalid» y «Required» proceden de los recursos de cadenas de la biblioteca (tanrei_invalid, tanrei_required). Sustitúyelas en tus recursos para traducirlas.
  • En la web, Safari en iOS amplía una entrada cuyo texto es menor de 16 px. Los campos del sistema predeterminado usan texto de 16 px en ambos tamaños; una capa que lo reduzca hace que vuelva la ampliación.