Formularios reactivos en Ionic 8: guía completa (2026)

Los formularios reactivos de Ionic (con Angular) te permiten definir, validar y enviar un formulario desde el codigo TypeScript de forma tipada y escalable, en lugar de atarlo todo a la plantilla. En esta guia, actualizada a Ionic 8 con componentes standalone, montamos un formulario reactivo paso a paso: creacion con FormBuilder e inject(), validaciones, mensajes de error, grupos anidados y listas dinamicas con FormArray.

Actualizado: julio 2026 · Ionic 8.8 + Angular 20/21, componentes standalone y sintaxis de control de flujo @if/@for.

Que son los formularios reactivos y cuando usarlos

En la app de acertar numeros usamos [(ngModel)] para el data binding entre la vista y el controlador. Ese enfoque (los formularios template-driven) es comodo para cosas pequenas, pero en formularios con muchos campos y validaciones se vuelve dificil de mantener.

Los formularios reactivos invierten el planteamiento: el formulario vive en el codigo como un modelo tipado y la plantilla solo se conecta a el. A cambio ganas validacion centralizada, tipado estricto, pruebas mas faciles y control total sobre el estado del formulario (valid, dirty, touched…).

Template-driven (ngModel) Reactivos (FormGroup)
La logica vive en la plantilla La logica vive en el componente
Ideal para formularios simples Ideal para formularios complejos y dinamicos
Validacion desperdigada en el HTML Validacion centralizada y testeable

Preparar el proyecto en Ionic 8

Creamos un proyecto en blanco. Ionic 8 genera por defecto una app con Angular y componentes standalone, asi que ya no necesitas declarar modulos (NgModule) para cada pagina:

ionic start formulario blank --type=angular
cd formulario
ionic info

En el momento de actualizar esta guia (julio de 2026) estas son las versiones que uso: Ionic 8.8, Angular 20/21 y TypeScript 5.x. Los formularios reactivos forman parte de @angular/forms, que ya viene con el proyecto.

Crear el formulario con FormBuilder e inject()

En una app standalone de Ionic 8 ya no importamos ReactiveFormsModule en un modulo: lo importamos directamente en el imports del componente. Los componentes de Ionic se importan desde @ionic/angular/standalone. Y en lugar de inyectar por constructor uso la funcion inject(), mas limpia.

Este es el componente formulario.page.ts completo:

import { Component, inject } from '@angular/core';
import { ReactiveFormsModule, FormBuilder, Validators } from '@angular/forms';
import {
  IonHeader, IonToolbar, IonTitle, IonContent,
  IonList, IonItem, IonInput, IonButton, IonNote,
} from '@ionic/angular/standalone';

@Component({
  selector: 'app-formulario',
  templateUrl: './formulario.page.html',
  standalone: true,
  imports: [
    ReactiveFormsModule,
    IonHeader, IonToolbar, IonTitle, IonContent,
    IonList, IonItem, IonInput, IonButton, IonNote,
  ],
})
export class FormularioPage {
  private fb = inject(FormBuilder);

  // .nonNullable evita que los controles puedan valer null
  // y hace el formulario mas facil de tipar.
  form = this.fb.nonNullable.group({
    nombre: ['', [Validators.required, Validators.minLength(3)]],
    email: ['', [Validators.required, Validators.email]],
  });

  // getters para leer los controles comodamente en la plantilla
  get nombre() { return this.form.controls.nombre; }
  get email() { return this.form.controls.email; }

  enviar() {
    if (this.form.invalid) {
      this.form.markAllAsTouched();
      return;
    }
    console.log(this.form.getRawValue());
  }
}

Fijate en this.fb.nonNullable.group(...): con la version no anulable del FormBuilder, TypeScript sabe que nombre y email son siempre string (nunca null), asi te ahorras comprobaciones y aprovechas los formularios estrictamente tipados de Angular.

Y esta es la plantilla formulario.page.html. En Ionic 8 el ion-input ya trae su propia etiqueta con label y labelPlacement, no hace falta un ion-label aparte:

<ion-header>
  <ion-toolbar>
    <ion-title>Formulario</ion-title>
  </ion-toolbar>
</ion-header>

<ion-content class="ion-padding">
  <form [formGroup]="form" (ngSubmit)="enviar()">
    <ion-list>
      <ion-item>
        <ion-input
          label="Nombre"
          labelPlacement="floating"
          formControlName="nombre"
          type="text">
        </ion-input>
      </ion-item>

      <ion-item>
        <ion-input
          label="Email"
          labelPlacement="floating"
          formControlName="email"
          type="email">
        </ion-input>
      </ion-item>
    </ion-list>

    <ion-button expand="block" type="submit" [disabled]="form.invalid">
      Enviar
    </ion-button>
  </form>
</ion-content>

Con esto ya tienes un formulario reactivo funcional: el boton se deshabilita mientras el formulario no sea valido y al enviar imprime los valores por consola.

Validacion y mensajes de error

Las validaciones se declaran junto a cada control con Validators. Los mas habituales: required, minLength, maxLength, email y pattern (para expresiones regulares). Para mostrar el error solo cuando tenga sentido, comprobamos que el campo se haya tocado (touched) y sea invalido. Uso la sintaxis moderna de control de flujo de Angular (@if):

<ion-item>
  <ion-input label="Email" labelPlacement="floating"
             formControlName="email" type="email">
  </ion-input>
</ion-item>

@if (email.touched && email.invalid) {
  <ion-note color="danger" class="ion-padding-start">
    @if (email.errors?.['required']) { El email es obligatorio. }
    @if (email.errors?.['email']) { Introduce un email valido. }
  </ion-note>
}

Como email es un getter que devuelve el control, en la plantilla accedes directamente a email.touched, email.invalid o email.errors sin repetir form.get('email') por todos lados.

Agrupar campos: grupos anidados (FormGroup dentro de FormGroup)

Cuando un bloque de campos va junto (por ejemplo una direccion), lo agrupas en un subgrupo. Asi el modelo queda ordenado y puedes validar o resetear todo el bloque de golpe:

form = this.fb.nonNullable.group({
  nombre: ['', Validators.required],
  direccion: this.fb.nonNullable.group({
    calle:  ['', Validators.required],
    ciudad: ['', Validators.required],
  }),
});

En la plantilla envuelves esos campos con formGroupName:

<div formGroupName="direccion">
  <ion-item>
    <ion-input label="Calle" labelPlacement="floating"
               formControlName="calle"></ion-input>
  </ion-item>
  <ion-item>
    <ion-input label="Ciudad" labelPlacement="floating"
               formControlName="ciudad"></ion-input>
  </ion-item>
</div>

Listas de campos dinamicas con FormArray

Cuando no sabes cuantos campos habra (varios telefonos, varias tareas…), usas un FormArray: una lista de controles a la que puedes anadir o quitar elementos en tiempo real. Anadimos un array de telefonos al formulario:

import { FormArray } from '@angular/forms';

form = this.fb.nonNullable.group({
  nombre: ['', Validators.required],
  telefonos: this.fb.array([this.crearTelefono()]),
});

private crearTelefono() {
  return this.fb.nonNullable.control('', Validators.required);
}

get telefonos(): FormArray {
  return this.form.controls.telefonos;
}

addTelefono()          { this.telefonos.push(this.crearTelefono()); }
removeTelefono(i: number) { this.telefonos.removeAt(i); }

Y en la plantilla recorremos el array con @for y formArrayName:

<div formArrayName="telefonos">
  @for (control of telefonos.controls; track $index) {
    <ion-item>
      <ion-input [formControlName]="$index"
                 label="Telefono" labelPlacement="floating">
      </ion-input>
      <ion-button slot="end" fill="clear" color="danger"
                  (click)="removeTelefono($index)">Quitar</ion-button>
    </ion-item>
  }
</div>

<ion-button expand="block" fill="outline" (click)="addTelefono()">
  Anadir telefono
</ion-button>

Enviar el formulario y leer los valores

En el metodo enviar() lo primero es comprobar la validez. Si el usuario no ha tocado nada, marcamos todo como touched para que aparezcan los mensajes de error; si es valido, leemos los datos. Con formularios nonNullable conviene usar getRawValue(), que te devuelve tambien los controles deshabilitados y con el tipo correcto:

enviar() {
  if (this.form.invalid) {
    this.form.markAllAsTouched();
    return;
  }

  const datos = this.form.getRawValue();
  // datos.nombre y datos.email vienen tipados como string
  console.log(datos);

  // this.form.reset(); // para limpiar tras enviar
}

Y en 2026, que hay de los Signal Forms

Si sigues Angular de cerca habras oido hablar de los Signal Forms, el nuevo enfoque basado en signals que Angular esta incorporando en las versiones 21/22. La idea es prometedora, pero a dia de hoy (julio de 2026) siguen en fase experimental / developer preview. Para produccion, los formularios reactivos que has visto aqui siguen siendo la opcion estable y recomendada, y Angular ya ofrece puentes de interoperabilidad para migrar poco a poco cuando los Signal Forms se estabilicen. Es decir: lo que aprendes en este tutorial te sirve hoy y no lo tiras manana.

Preguntas frecuentes

Cual es la diferencia entre formularios reactivos y template-driven?

En los template-driven (ngModel) la logica del formulario vive en el HTML; en los reactivos vive en el componente como un modelo tipado. Los reactivos escalan mucho mejor cuando hay validaciones, campos dinamicos o quieres testear.

Como valido un campo con una expresion regular?

Con Validators.pattern(/tu-regex/) junto al resto de validadores del control.

Como limpio o reseteo el formulario tras enviarlo?

Llamando a this.form.reset(). Con formularios nonNullable, cada control vuelve a su valor inicial en lugar de a null.

Tengo que importar ReactiveFormsModule en un modulo?

En Ionic 8 con componentes standalone, no: lo importas directamente en el array imports del propio componente.

Quieres seguir aprendiendo Ionic con orden? Si quieres saber mas sobre el desarrollo de aplicaciones con Ionic, en esta entrada puedes ver el indice de contenidos de mi libro:

📚 Libro: Desarrollo de aplicaciones moviles multiplataforma con Ionic

Puede que en este ejemplo pequeno de dos campos no le veas mucho ahorro, pero en formularios complejos con muchos campos, validaciones y bloques dinamicos los formularios reactivos hacen el codigo mucho mas comodo de mantener y de leer.

Si quieres una base solida antes de seguir, repasa la introduccion a Ionic y el capitulo de navegacion por tabs del tutorial.

💼 Necesitas una app hecha a medida? Si prefieres que la desarrolle yo, pideme un presupuesto para tu app sin compromiso.

Muchas gracias por leer, y como siempre, cualquier duda en los comentarios.

Un saludo, y si aún no lo has hecho no olvides suscribirte a mi blog para no perderte los próximos posts  :-),

También puedes seguirme en Twitter en ‎@revi_apps y no olvides que me ayudas mucho si compartes este post en las redes sociales.

1 comentario en “Formularios reactivos en Ionic 8: guía completa (2026)”

  1. Muy buenas tardes con el ejecutor tengo el visual code studio y me gustaría que me envíen dónde se tiene que escribir los código si es en la cabecera o en otro sitio

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

Scroll al inicio