# TagsInput

> Un campo de etiquetas libres: se escribe, Enter o coma la agrega como un `Tag`, y Backspace quita la última.

```tsx
import { TagsInput } from "sebs7n-ui/tags-input"
```

## Ejemplos

### Etiquetas de una factura

Enter o coma agregan; Backspace con el campo vacío quita la última. Las repetidas no entran.

```tsx
import { Field, FieldDescription, FieldError, FieldLabel } from "sebs7n-ui/field"
import { TagsInput } from "sebs7n-ui/tags-input"

function Basic() {
  return (
    <div className="w-full max-w-md">
      <Field name="tags">
        <FieldLabel>Etiquetas</FieldLabel>
        <TagsInput defaultValue={["mayorista", "urgente"]} max={5} placeholder="Agregar etiqueta" />
        <FieldDescription>Hasta 5. Enter o coma para agregar.</FieldDescription>
        <FieldError />
      </Field>
    </div>
  )
}
```

### Correos con validación

`validate` revisa cada uno antes de agregarlo; pegar una lista la separa por comas y renglones.

```tsx
import { Field, FieldLabel } from "sebs7n-ui/field"
import { TagsInput } from "sebs7n-ui/tags-input"

function Emails() {
  return (
    <div className="w-full max-w-md">
      <Field name="cc">
        <FieldLabel>Copia a</FieldLabel>
        <TagsInput defaultValue={["cobranzas@acme.com"]} placeholder="correo@cliente.com" size="lg" validate={email} />
      </Field>
    </div>
  )
}
```

### Alícuotas con coma decimal

`delimiters={["Enter"]}` deja la coma dentro del valor; `addOnBlur` agrega lo escrito al salir o al enviar, sin Enter.

```tsx
import { Field, FieldDescription, FieldLabel } from "sebs7n-ui/field"
import { TagsInput } from "sebs7n-ui/tags-input"

function Decimals() {
  return (
    <div className="w-full max-w-md">
      <Field name="rates">
        <FieldLabel>Alícuotas de IVA (%)</FieldLabel>
        <TagsInput addOnBlur defaultValue={["10,5", "21"]} delimiters={["Enter"]} placeholder="27" />
        <FieldDescription>Enter para agregar; lo escrito entra al salir del campo.</FieldDescription>
      </Field>
    </div>
  )
}
```

## Props

### TagsInput

| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
| `addOnBlur` | `boolean` | `false` | Lo escrito sin Enter entra al salir del campo y antes de enviar o leer el form (validado; si no entra, no se envía). Default `false`; en un formulario, **usalo en `true`**. |
| `aria-describedby` | `string` | — | El `id` de una ayuda. Los errores se suman solos. |
| `aria-label` | `string` | — | Nombra el campo y la lista de etiquetas. |
| `aria-labelledby` | `string` | — | El `id` del elemento que nombra el campo, si no es un `<label>`. |
| `defaultValue` | `string[]` | `[]` | Las etiquetas al montar, sin controlar. |
| `delimiters` | `string[]` | — | Qué separa etiquetas: `"Enter"` (la tecla) y caracteres. Default: Enter y coma. `["Enter"]` para valores con coma decimal. |
| `disabled` | `boolean` | — | Apaga el campo y los × de las etiquetas. |
| `id` | `string` | — | El `id` del campo de texto, para un `<Label htmlFor>`. |
| `labels` | `Partial<TagsInputLabels>` | — | Textos: `remove`, `added`, `removed`, `duplicate` y `tooMany`. Por defecto, `tagsInputLabels`. |
| `max` | `number` | — | Cuántas como mucho. La que no entra se avisa en línea. |
| `name` | `string` | — | El nombre con el que viajan en un formulario: una etiqueta por campo, como un grupo de checkboxes. |
| `onValueChange` | `(value: string[]) => void` | — | Avisa la lista entera cada vez que se agrega o se quita una. |
| `placeholder` | `string` | — | Lo que dice el campo vacío. |
| `required` | `boolean` | `false` | Sin etiquetas no se puede enviar: dentro de un `Form`, el campo queda inválido y `Form` lo enfoca. |
| `size` | `"sm" \| "md" \| "lg"` | `"md"` | 28, 36 (default) o 40 de alto mínimo, como los campos; crece con las filas de etiquetas. |
| `validate` | `(tag: string, tags: readonly string[]) => string` | — | Una validación por etiqueta, antes de agregarla: el texto que devuelve es el error en línea («ana no es un correo») y la etiqueta no entra (el texto queda en el campo para corregirlo). |
| `value` | `string[]` | — | Las etiquetas, controlado. |
| `className` | `string` | — | Clases de la superficie. |

## Teclado

| Tecla | Qué hace |
|---|---|
| Enter · , | Agregan lo escrito como etiqueta (Enter vacío sigue enviando el formulario). Se cambian con `delimiters`. |
| Backspace | Con el campo vacío, quita la última etiqueta. |
| Tab | Del campo a los × de cada etiqueta. |

## Accesibilidad

- El campo de texto lleva el nombre (`aria-label` o `FieldLabel`); las etiquetas son una lista con el mismo nombre y cada × se llama «Quitar urgente».
- Lo que no entra (repetida, `max`, `validate`) se muestra abajo con `role="alert"`, el campo queda `aria-invalid` y el texto sigue en el campo para corregirlo. Agregar y quitar se anuncian por una región viva.

## Reglas de uso

- Texto libre: correos a copiar, palabras clave, etiquetas de un producto. Para elegir de una lista, `Combobox multiple`.
- Pegar inserta en el cursor, como en cualquier campo, y después separa por comas, punto y coma, tabs y renglones.
- `validate(tag, tags)` valida cada una antes de agregarla; `max` pone el tope. Las repetidas no entran, sin importar mayúsculas («Urgente» si ya está «urgente»); una lista controlada con repetidas se muestra igual.
- Con `name` (o el del `Field`) cada etiqueta viaja como un campo del form, como un grupo de checkboxes; en `onFormSubmit` de `Form` llega la lista. `required` no deja enviar sin etiquetas.
- **En un formulario con «Guardar», usá `addOnBlur`.** Sin eso, lo escrito sin Enter se pierde al enviar. Con `addOnBlur`, entra al salir del campo y antes de que el form se envíe o se lea (`onFormSubmit`, `onSubmit`, `new FormData(form)`), validado como con Enter: si no entra, queda con su error y el form no se envía. Es `false` por defecto solo para no cambiar el comportamiento en una patch.
- `delimiters` elige qué separa: `"Enter"` es la tecla, el resto son caracteres. `["Enter"]` deja pasar comas decimales («38,5»); pegar separa por los mismos y por renglones. Sin `delimiters`: Enter y coma, y al pegar también punto y coma y tabs.
- Solo por subpath (`sebs7n-ui/tags-input`).

## Relacionados

[tag](/docs/components/tag.md) · [combobox](/docs/components/combobox.md) · [field](/docs/components/field.md)
