# Campo de texto

> Un campo de texto controlado con icono, placeholder y modo contraseña. Componente de Pyzed para GUIs de escritorio en Python, con ejemplos y API.

Source: https://albakore.github.io/pyzed/es/library/input/

:::tip[En pocas palabras]
Una caja donde la gente escribe una línea de texto: un nombre, un correo, una contraseña.
:::

Un campo de texto de una línea con el estilo del tema. Es **controlado**: muestra `value` y avisa de cada tecla a `on_input`, así que guardas el texto en tu estado y lo devuelves en `view()`. `on_submit` se ejecuta al pulsar Enter.

`ui.input` · Categoría: [Formularios](https://albakore.github.io/pyzed/es/library/#formularios) · [Referencia completa →](https://albakore.github.io/pyzed/es/reference/ui/#input)

**Código:**

```python
pz.column([
    ui.input("", on_input, placeholder="Project name"),
    ui.input("ada@example.com", on_input, icon="mail"),
    ui.input("hunter2", on_input, secure=True, icon="lock"),
], spacing=10, width=360)
```

## Cuándo usarlo

- Para nombres, rutas, búsquedas, correos y contraseñas (`secure=True`).
- Para texto de varias líneas o código usa el [Editor](https://albakore.github.io/pyzed/es/library/editor/).
- Dale un `id` para enfocarlo desde código con `pz.Command.focus(id)`.

## Uso

```python
import pyzed as pz
from pyzed import ui

class Form(pz.App):
    def __init__(self):
        self.name = ""

    def view(self):
        return ui.input(self.name, lambda text: setattr(self, "name", text),
                        placeholder="Project name", on_submit=self.create, id="name")

    def on_start(self):
        return pz.Command.focus("name")
```

## Variantes

:::note[Sobre estas capturas]
Cada captura la graba pyzed mismo, fuera de pantalla a 2x, en One Dark o One Light según el tema de este sitio, y recortada al componente para que se vea a su tamaño real. El puntero pasa por encima, pulsa o escribe en él; un componente que no reacciona al puntero recorre algunos temas. Con movimiento reducido ves el primer fotograma. Abre **Código** bajo una captura para ver el fragmento que la dibuja; los nombres libres como `on_save` son tus propios callbacks.
:::

### Contenido

```python
ui.input("", on_input, placeholder="Project name", width=260)
```

```python
ui.input("Pyzed", on_input, width=260)
```

```python
ui.input("ada@example.com", on_input, icon="mail", width=260)
```

```python
ui.input("hunter2", on_input, secure=True, icon="lock", width=260)
```

### Tamaño

```python
ui.input("Small", on_input, size="sm", width=260)
```

```python
ui.input("Medium", on_input, size="md", width=260)
```

```python
ui.input("Large", on_input, size="lg", width=260)
```

### Estilo

```python
ui.input("Borderless", on_input, borderless=True, width=260)
```

```python
ui.input("SELECT * FROM users", on_input, mono=True, width=260)
```

```python
ui.input("Can't edit me", width=260)
```

### Validación

Muestra los errores con `error=` de [Campo de formulario](https://albakore.github.io/pyzed/es/library/field/), junto al campo.

```python
ui.field("Email", ui.input("ada@", on_input, width=220), error="Enter a valid email")
```

### Estados y eventos

El foco, la pérdida de foco y las teclas vienen de los eventos comunes: `.on(focus=..., blur=..., key_down=...)`.

```python
ui.input("Locked", on_input, disabled=True, width=220)
```

```python
ui.input("Copy me, not edit me", on_input, readonly=True, width=220)
```

```python
ui.input("ada@", on_input, invalid=True, width=220)
```

```python
ui.input("pyzed", on_input, on_clear=on_clear, width=220)
```

```python
ui.input("12345678", on_input, max_length=8, width=220)
```

```python
ui.input("centered", on_input, align="center", width=220)
```

### Widget base

El widget `pz.*` de debajo: sin tema, todos los colores y tamaños son tuyos.

```python
pz.text_input("", placeholder="pz.text_input", on_input=on_input, width=260, padding=8,
              radius=8, border_color="#c678dd", focus_border_color="#e5c07b")
```

## Eventos

Campo de texto tiene **3 eventos propios**, en la tabla de abajo. Como todo widget, también tiene los **18 eventos comunes** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), que se conectan con `.on(...)`: mira [Eventos](https://albakore.github.io/pyzed/es/guides/events/) y [Eventos de cada componente](https://albakore.github.io/pyzed/es/library/events/).

| Evento | De | El handler recibe | Cuándo |
| --- | --- | --- | --- |
| `on_input` | `ui.input`, `pz.text_input` | `(text)` | Callable que recibe el texto nuevo en cada pulsación. |
| `on_submit` | `ui.input`, `pz.text_input` | `()` | Mensaje o callable que se envía al pulsar Enter. |
| `on_clear` | `ui.input` | `()` | Muestra una ✕ mientras hay texto; se envía al pulsarla. |

**El handler recibe** es lo que Pyzed le pasa a tu función: `()` es nada. Cualquier handler también puede ser un mensaje (un valor que no se puede llamar), que va a `update()`.

### Manejar los eventos

Los mismos eventos escritos de tres formas. **Imperativa**: métodos de la app que cambian `self`. **Declarativa**: los handlers producen mensajes y un único `update()` decide. **Funcional**: una función pura dibuja un estado inmutable y pide cambios con `set_state(...)`. Mira [Imperativo, declarativo y funcional](https://albakore.github.io/pyzed/es/guides/code-styles/).

**Imperativo:**

```python
class SignUp(pz.App):
    def __init__(self):
        self.email = ""
        self.sent = False

    def set_email(self, text):           # on_input: the new text on every keystroke
        self.email, self.sent = text, False

    def send(self):                      # on_submit: Enter
        self.sent = "@" in self.email

    def view(self):
        return pz.column([
            ui.input(self.email, self.set_email, placeholder="Email", icon="mail", id="email",
                     on_submit=self.send, on_clear=lambda: self.set_email(""),
                     invalid=bool(self.email) and "@" not in self.email),
            ui.label("Thanks!" if self.sent else "Press Enter to send"),
        ], spacing=8, width=320)

    def on_start(self):
        return pz.Command.focus("email")
```

**Declarativo:**

```python
from dataclasses import dataclass

@dataclass
class Typed:
    text: str

class SignUp(pz.App):
    email = ""
    sent = False

    def update(self, message):
        match message:
            case Typed(text):
                self.email, self.sent = text, False
            case "send":
                self.sent = "@" in self.email
            case "clear":
                self.email = ""

    def view(self):
        return ui.input(self.email, Typed, placeholder="Email", icon="mail",
                        on_submit="send", on_clear="clear")
```

**Funcional:**

```python
from dataclasses import dataclass

@dataclass(frozen=True)
class State:
    email: str = ""
    sent: bool = False

def view(state, set_state):
    valid = "@" in state.email
    return pz.column([
        ui.input(state.email, lambda text: set_state(email=text, sent=False), placeholder="Email",
                 on_submit=lambda: set_state(sent=valid), invalid=bool(state.email) and not valid),
        ui.label("Thanks!" if state.sent else "Press Enter to send"),
    ], spacing=8, width=320)
```

## Propiedades y API

### `ui.input`

```python
input(
    value,
    on_input=None,
    *,
    placeholder='',
    icon=None,
    on_submit=None,
    on_clear=None,
    id=None,
    size='md',
    secure=False,
    width='fill',
    borderless=False,
    mono=False,
    disabled=False,
    readonly=False,
    invalid=False,
    max_length=None,
    align='start',
    theme=None,
)
```

Un campo de texto. El foco, la pérdida de foco y las teclas vienen de los eventos comunes: `.on(focus=..., blur=..., key_down=...)`.

| Propiedad | Por defecto | Descripción |
| --- | --- | --- |
| `value` | *obligatorio* | Texto actual. |
| `placeholder` | `""` | Texto de ayuda cuando está vacío. |
| `icon` | `None` | Nombre de un icono de Lucide (`pyzed icons` los lista). |
| `id` | `None` | Identificador estable para enfocarlo o desplazarlo con un `Command`. |
| `size` | `"md"` | `"sm"`, `"md"` o `"lg"`. |
| `secure` | `False` | Oculta el texto. |
| `width` | `"fill"` | Ancho: píxeles, `"fill"`, `"shrink"` o `"fill:N"` (proporción). |
| `borderless` | `False` | Sin borde ni fondo (como en la paleta de comandos). |
| `mono` | `False` | Usa la fuente monoespaciada (IBM Plex Mono). |
| `disabled` | `False` | Lo atenúa e ignora lo que se escribe. |
| `readonly` | `False` | Se puede seleccionar y copiar, pero no cambiar. |
| `invalid` | `False` | Pinta el borde con el color de error. |
| `max_length` | `None` | Ignora los cambios más largos que esto. |
| `align` | `"start"` | Alineación del texto: `"start"`, `"center"` o `"end"`. |
| `theme` | `None` | Tema a usar en lugar del actual (`pyzed.theme.current()`). |

Eventos: `on_input`, `on_submit`, `on_clear` ([eventos](#eventos)).

[Referencia completa →](https://albakore.github.io/pyzed/es/reference/ui/#input)

### `pz.text_input`

```python
text_input(
    value,
    *,
    placeholder='',
    on_input=None,
    on_submit=None,
    id=None,
    size=None,
    font=None,
    padding=None,
    width=None,
    secure=False,
    icon=None,
    icon_size=None,
    bg=None,
    border_color=None,
    hover_border_color=None,
    focus_border_color=None,
    border_width=None,
    radius=None,
    color=None,
    placeholder_color=None,
    selection_color=None,
    icon_color=None,
    align_x=None,
)
```

Un campo de texto controlado: muestra `value` y te avisa de los cambios con `on_input`. Para el campo con tema usa `ui.input`.

| Propiedad | Por defecto | Descripción |
| --- | --- | --- |
| `value` | *obligatorio* | Texto actual. |
| `placeholder` | `""` | Texto de ayuda cuando está vacío. |
| `id` | `None` | Identificador estable para enfocarlo o desplazarlo con un `Command`. |
| `size` | `None` | Tamaño de la fuente. |
| `font` | `None` | Familia de la fuente. |
| `padding` | `None` | Relleno interior: `8`, `(vertical, horizontal)` o `(arriba, derecha, abajo, izquierda)`. |
| `width` | `None` | Ancho: píxeles, `"fill"`, `"shrink"` o `"fill:N"` (proporción). |
| `secure` | `False` | Oculta el texto (contraseñas). |
| `icon` | `None` | Carácter del icono (usa `pyzed.icons.glyph(nombre)`). |
| `icon_size` | `None` | Tamaño del icono. |
| `bg` | `None` | Color de fondo (`"#rrggbb[aa]"`, `(r, g, b[, a])` o `"transparent"`). |
| `border_color` | `None` | Color del borde. |
| `hover_border_color` | `None` | Color del borde al pasar el ratón. |
| `focus_border_color` | `None` | Color del borde con el foco. |
| `border_width` | `None` | Grosor del borde en píxeles. |
| `radius` | `None` | Radio de las esquinas: un número o `(sup_izq, sup_der, inf_der, inf_izq)`. |
| `color` | `None` | Color del texto o del icono. |
| `placeholder_color` | `None` | Color del placeholder. |
| `selection_color` | `None` | Color de la selección. |
| `icon_color` | `None` | Color del icono. |
| `align_x` | `None` | Alineación horizontal: `"start"`/`"left"`, `"center"`, `"end"`/`"right"`. |

Eventos: `on_input`, `on_submit` ([eventos](#eventos)).

[Referencia completa →](https://albakore.github.io/pyzed/es/reference/widgets/#text_input)

## Relacionados

- [Campo de búsqueda](https://albakore.github.io/pyzed/es/library/search-input/): Un campo con lupa, para filtrar.
- [Campo de formulario](https://albakore.github.io/pyzed/es/library/field/): Una fila de ajustes: título y descripción a la izquierda, control a la derecha.
- [Campo numérico](https://albakore.github.io/pyzed/es/library/number-field/): Un número con botones −/+, límites, paso y sufijo.
