# Cómo montar un formulario responsivo rótulo:campo

> Alinear rótulos y campos en columnas proporcionales con GridLayout.

Source: https://crossfly.dev/es/docs/cookbook/forms/formulario-responsivo — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# Cómo montar un formulario responsivo rótulo:campo

**Propósito.** Alinear pares rótulo + campo en dos columnas proporcionales (ej.: 35% para el rótulo, 65% para el campo) que se adaptan al ancho de la pantalla, usando `GridLayout`.

## APIs usadas
- `new GridLayout(Position h, Position v)` — crea el grid con alineación horizontal y vertical de las filas (`START`, `CENTER`, `END`). El constructor sin argumentos usa `START, START`.
- `grid.add(Object... v)` — añade una fila. **Formato: todos los anchos primero, luego todos los componentes.** Los anchos son fracciones del ancho total (`0.35f` = 35%); `0f` = auto-width (el componente decide). El número de anchos debe igualar el de componentes.
- Cada fila calcula su propia altura por la del componente más alto; las filas se apilan verticalmente.

> Orden de los argumentos en `add`: `add(0.35f, 0.65f, label, campo)` — los dos anchos van **antes** de los dos componentes, no intercalados. Pasar `add(label, 0.35f, campo, 0.65f)` lanza `UIException`.

> Responsividad: como los anchos son fracciones, el layout se ajusta solo cuando la pantalla cambia de tamaño. Usa `Screen` (no `Gdx.graphics`) si necesitas medidas absolutas.

## Ejemplo completo (copiar, pegar y ejecutar)
```java
package com.exemplo;

import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;
import dev.crossfly.ui.style.*;   // TextFieldStyle (config en el estilo)

/** Pantalla principal ejecutable. Apunta el launcher (classname) y corre: gradlew :lwjgl3:run */
public class MainWindow extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();

      GridLayout form = new GridLayout(Position.START, Position.START);
      setLayout(form);

      // Fila: etiqueta (35%) + campo (65%)
      TextField nome  = new TextField("");
      TextField email = new TextField("");
      form.add(0.35f, 0.65f, new Label("Nome"),  nome);
      form.add(0.35f, 0.65f, new Label("Email"), email);

      // Campo con máscara en la misma estructura
      TextField cpf = new TextField("");
      cpf.<TextFieldStyle>getStyle()
         .mask("999.999.999-99".toCharArray())
         .mode(EditMode.NUMERIC, true);
      form.add(0.35f, 0.65f, new Label("CPF"), cpf);

      // Fila de resultado
      Label resultado = new Label("");
      form.add(0.35f, 0.65f, new Label(""), resultado);

      // Fila de auto-width: dos botones dimensionados por el contenido
      Button salvar = new Button("Salvar");
      salvar.onAction(o ->
         resultado.setText(nome.getText() + " · " + cpf.getTextWithoutMask()));
      form.add(0f, 0f, new Button("Cancelar"), salvar);
   }
}
```

> El fragmento de abajo muestra **solo el núcleo**. Para ejecutarlo, colócalo en el esqueleto `MainWindow` de arriba.

## Fragmento mínimo
```java
import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;
import dev.crossfly.ui.style.*;
import static dev.crossfly.ui.UIConstants.Position;
import static dev.crossfly.ui.UIConstants.EditMode;

GridLayout form = new GridLayout(Position.START, Position.START);

// Fila: etiqueta (35%) + campo (65%)
form.add(0.35f, 0.65f, new Label("Nome"),  new TextField(""));
form.add(0.35f, 0.65f, new Label("Email"), new TextField(""));

// Campo con máscara en la misma estructura
TextField cpf = new TextField("");
cpf.<TextFieldStyle>getStyle()
   .mask("999.999.999-99".toCharArray())
   .mode(EditMode.NUMERIC, true);
form.add(0.35f, 0.65f, new Label("CPF"), cpf);

// Fila de auto-width: dos botones dimensionados por el contenido
form.add(0f, 0f, new Button("Cancelar"), new Button("Salvar"));
```

Añade el `GridLayout` al contenedor/ventana de la pantalla conforme al patrón de tu componente padre.

## Profundiza
- [Campos de texto](/docs/ui/forms-and-input/text-fields) · [Foco y validación](/docs/ui/forms-and-input/focus-and-validation)
- Recetas hermanas: [Máscara de CPF/CEP/fecha](/docs/cookbook/forms/mascara-cpf) · [Campo de contraseña](/docs/cookbook/forms/campo-de-senha)
