Ir al contenido

Componentes · Ola 1 · Formularios

Input

Recibe texto de una línea: nombres, correos, búsquedas, cifras. Es de solo línea: sin caja ni relleno, el límite es la línea inferior y el foco la enciende. Dentro de un Field toma de él su etiqueta, su descripción y sus estados.

import { Input } from '@archeblack/ui';

Ejemplos

Dentro de un Field

El uso de todos los días: Field pone la etiqueta y conecta el campo.

Svelte
<script lang="ts">
	import { Field, Input } from '@archeblack/ui';

	let name = $state('');
</script>

<div style:width="min(100%, 20rem)">
	<Field label="Nombre del proyecto">
		<Input bind:value={name} placeholder="Portal de clientes" />
	</Field>
</div>

Suelto

Sin Field, el nombre va en aria-label. Una búsqueda es el caso típico.

Svelte
<script lang="ts">
	import { Input } from '@archeblack/ui';
	import { IconSearch } from '@archeblack/ui/icons';

	let query = $state('');
</script>

<!-- Suelto, sin Field: el nombre accesible va en aria-label. -->
<div style:width="min(100%, 20rem)">
	<Input
		type="search"
		icon={IconSearch}
		bind:value={query}
		placeholder="Buscar proyectos"
		aria-label="Buscar proyectos"
	/>
</div>

Ícono y sufijo

icon al inicio, decorativo; suffix al final, para una unidad o un dominio.

.arche.app
GB
Svelte
<script lang="ts">
	import { Field, Input } from '@archeblack/ui';
	import { IconMail } from '@archeblack/ui/icons';

	let email = $state('');
	let subdomain = $state('portal-clientes');
	let storage = $state(20);
</script>

<div style:display="grid" style:gap="var(--arche-spacing-6)" style:width="min(100%, 20rem)">
	<Field label="Correo">
		<Input type="email" icon={IconMail} bind:value={email} placeholder="nombre@empresa.com" />
	</Field>
	<Field label="Subdominio">
		<Input bind:value={subdomain} suffix=".arche.app" />
	</Field>
	<Field label="Espacio">
		<Input type="number" bind:value={storage} min={1} max={500} suffix="GB" />
	</Field>
</div>

Tallas

sm, md y lg, por alto. Los mismos altos que Button, para ponerlos en fila. El ícono mide 16 px en sm y md, y 20 px en lg. xl es para una búsqueda (ver el ejemplo siguiente).

Svelte
<script lang="ts">
	import { Input } from '@archeblack/ui';
	import { IconSearch } from '@archeblack/ui/icons';
</script>

<!-- El ícono mide 16 px en sm y md, y 20 px en lg. -->
<div style:display="grid" style:gap="var(--arche-spacing-6)" style:width="min(100%, 20rem)">
	<Input size="sm" icon={IconSearch} placeholder="Talla sm, 28 px" aria-label="Talla sm" />
	<Input icon={IconSearch} placeholder="Talla md, 36 px" aria-label="Talla md" />
	<Input size="lg" icon={IconSearch} placeholder="Talla lg, 44 px" aria-label="Talla lg" />
</div>

Búsqueda a pantalla completa

size="xl" es la línea grande de una búsqueda (52 px, 22 px semibold condensado). El conteo va en el sufijo y liveSuffix lo anuncia; prueba «alma» o «el». Dentro de un diálogo a pantalla completa, en Dialog.

1 resultado
Svelte
<script lang="ts">
	import '@archeblack/ui/products/hermes.css';
	import { Input } from '@archeblack/ui';

	let query = $state('escucha');

	// Los títulos de Hermes, donde busca el campo.
	const titles = [
		'El Alma Pide Locura',
		'Lo que cambia cuando alguien escucha',
		'El Daimon en la Máquina',
		'El Doctor que Bailó con el Tiempo',
		'Lo Numinoso en CONTROL'
	];

	/** Sin mayúsculas ni tildes. */
	const fold = (text: string) => text.normalize('NFD').replace(/[̀-ͯ]/g, '').toLocaleLowerCase();

	const found = $derived(
		query.trim() ? titles.filter((title) => fold(title).includes(fold(query.trim()))).length : 0
	);
</script>

<!-- La línea de una búsqueda a pantalla completa: size="xl" (52 px, 22 px semibold condensado). El
     conteo va en el sufijo, en la letra de las etiquetas; liveSuffix lo anuncia al cambiar. -->
<div data-product="hermes" style:width="min(100%, var(--arche-layout-measure-narrow))">
	<Input
		size="xl"
		type="search"
		bind:value={query}
		aria-label="Buscar en Hermes"
		placeholder="Busca por título…"
		autocomplete="off"
		suffix={query.trim() ? `${found} ${found === 1 ? 'resultado' : 'resultados'}` : ''}
		liveSuffix
	/>
</div>

Estados

Vacío con placeholder, con valor, inválido y deshabilitado. Pasa el cursor y haz clic para ver el hover y el foco.

Usa solo minúsculas, números y guiones.

Svelte
<script lang="ts">
	import { Field, Input } from '@archeblack/ui';
</script>

<div style:display="grid" style:gap="var(--arche-spacing-6)" style:width="min(100%, 20rem)">
	<Field label="Vacío">
		<Input placeholder="nombre@empresa.com" />
	</Field>
	<Field label="Con valor">
		<Input value="Portal de clientes" />
	</Field>
	<Field label="Inválido" error="Usa solo minúsculas, números y guiones.">
		<Input value="portal clientes" />
	</Field>
	<Field label="Deshabilitado" disabled>
		<Input value="prj_7f3a92c1" />
	</Field>
</div>

Props

Props de Input
PropDescripción
bind:value? string | number | null Valor del campo. Con type="number" es un número, o null si el campo está vacío.
type? 'text' | 'email' | 'password' | 'search' | 'tel' | 'url' | 'number' Por defecto 'text'Tipo de texto. Casillas, radios e interruptores tienen su propio componente.
size? 'sm' | 'md' | 'lg' | 'xl' Por defecto 'md'Talla por alto: sm 28 px (texto de 13 px), md 36 px y lg 44 px (texto de 15 px), los mismos altos que Button. xl mide 52 px, con texto de 22 px semibold condensado al 75 %: es la línea de una búsqueda a pantalla completa, y su sufijo va en la letra de las etiquetas.
icon? IconGlyph Ícono decorativo al inicio, de @archeblack/ui/icons. Mide 16 px en sm y md, y 20 px en lg y xl.
suffix? string Texto fijo al final: una unidad (GB) o un dominio (.arche.app). No forma parte del valor y describe al campo. En xl, el conteo de resultados de una búsqueda, en la mono de 12 px en mayúsculas.
liveSuffix? boolean Por defecto falseAnuncia el sufijo cada vez que cambia (role="status"), como el conteo de resultados de una búsqueda. La región existe desde el principio, aunque el sufijo esté vacío, para que el primer cambio también se anuncie.
invalid? boolean Por defecto falseMarca el valor como inválido (aria-invalid). Dentro de un Field lo decide su error.
bind:ref? HTMLInputElement | null El <input>, para enfocarlo desde el código.
class? ClassValue Clases del producto; se suman a arche-input, el contenedor que dibuja la línea (por ejemplo, para darle un ancho).
...rest HTMLInputAttributes Cualquier otro atributo va al <input>: name, placeholder, autocomplete, required, disabled, oninput… Dentro de un Field, required y disabled también pueden venir de él.

Accesibilidad

  • Es un <input> nativo: el teclado, el autocompletado y los lectores de pantalla funcionan sin nada extra.
  • Necesita un nombre: dentro de un Field lo da la etiqueta; suelto, aria-label, aria-labelledby o un <label for> propio. En desarrollo, un Input suelto sin nombre avisa por consola.
  • El ícono es decorativo. El sufijo describe al campo (aria-describedby), así «GB» o «.arche.app» se leen junto a él. Con liveSuffix es además una región status: el conteo de una búsqueda se anuncia cuando cambia, sin mover el foco del campo.
  • xl sigue siendo de solo línea: la misma línea de 1 px al 44 % (3:1), al 56 % en hover y encendida con el foco. Solo cambian el alto y la letra.
  • La línea llega a 3:1 contra toda capa, y 3:1 también en hover. El foco la enciende y deja caer un halo; con el brillo en 0 queda la línea de 2 px.
  • Inválido no es solo color: dentro de un Field el mensaje lleva ícono y texto. Con foco, la línea de un campo inválido toma el color de foco y el halo es de peligro, así el campo que se corrige se distingue de los otros inválidos.
  • Con type="number" no hay flechas nativas: el valor cambia con las flechas arriba y abajo del teclado, y el lector lo anuncia como un campo numérico.
  • Deshabilitado, la línea es punteada: se ve, pero no se confunde con la línea sólida de un campo que se puede usar.
  • En colores forzados el foco engrosa la línea, porque la sombra desaparece.

Qué evitar

  • Un placeholder como etiqueta. Un Field con label, o aria-label si el campo va suelto (una búsqueda).
  • Encerrar el campo en una caja o darle fondo. Los campos de Arche son de solo línea. Si hace falta agrupar, se agrupa el formulario (una Card), no el campo.
  • Escribir la unidad dentro del valor («20 GB»). suffix="GB" y un type="number": el valor queda limpio.
  • type="number" para números que no se cuentan (teléfonos, códigos postales, tarjetas). type="tel" o inputmode="numeric" con type="text".
  • Un ícono al inicio que no agrega nada (un lápiz en cada campo). Úsalo solo cuando ayuda a reconocer el campo: buscar, correo, enlace.