Back to blog

    Angular Contact Form with Reactive Forms and HttpClient

    Build a contact form in Angular using ReactiveFormsModule and HttpClient. Includes validation, loading states, error handling, and submission to Formboost — no backend required.

    Angular Contact Form with Reactive Forms and HttpClient

    Angular's ReactiveFormsModule and HttpClient are the right tools for building robust contact forms. This guide shows how to build a complete contact form component in Angular — with validation, loading state, error handling, and submission to an external endpoint — no backend server required.

    Prerequisites

    • Angular v15+ project
    • ReactiveFormsModule and HttpClientModule imported

    Setup

    Add HttpClientModule to your app module (or use provideHttpClient() in standalone apps):

    1// app.module.ts
    2import { HttpClientModule } from '@angular/common/http';
    3
    4@NgModule({
    5  imports: [
    6    BrowserModule,
    7    ReactiveFormsModule,
    8    HttpClientModule,
    9  ],
    10})
    11export class AppModule {}

    For standalone components (Angular 17+):

    1// main.ts
    2import { provideHttpClient } from '@angular/common/http';
    3
    4bootstrapApplication(AppComponent, {
    5  providers: [provideHttpClient()],
    6});

    The Contact Form Component

    1// contact-form.component.ts
    2import { Component } from '@angular/core';
    3import { FormBuilder, FormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
    4import { HttpClient } from '@angular/common/http';
    5import { CommonModule } from '@angular/common';
    6
    7@Component({
    8  selector: 'app-contact-form',
    9  standalone: true,
    10  imports: [ReactiveFormsModule, CommonModule],
    11  template: `
    12    <div *ngIf="submitted; else formTemplate">
    13      <p>Thanks! We'll be in touch soon.</p>
    14    </div>
    15
    16    <ng-template #formTemplate>
    17      <form [formGroup]="form" (ngSubmit)="onSubmit()">
    18        <div>
    19          <label for="name">Name</label>
    20          <input id="name" type="text" formControlName="name" />
    21          <span *ngIf="f['name'].touched && f['name'].errors?.['required']">
    22            Name is required
    23          </span>
    24        </div>
    25
    26        <div>
    27          <label for="email">Email</label>
    28          <input id="email" type="email" formControlName="email" />
    29          <span *ngIf="f['email'].touched && f['email'].errors?.['required']">
    30            Email is required
    31          </span>
    32          <span *ngIf="f['email'].touched && f['email'].errors?.['email']">
    33            Enter a valid email address
    34          </span>
    35        </div>
    36
    37        <div>
    38          <label for="message">Message</label>
    39          <textarea id="message" formControlName="message" rows="5"></textarea>
    40        </div>
    41
    42        <p *ngIf="error" style="color: red">{{ error }}</p>
    43
    44        <button type="submit" [disabled]="submitting || form.invalid">
    45          {{ submitting ? 'Sending…' : 'Send Message' }}
    46        </button>
    47      </form>
    48    </ng-template>
    49  `,
    50})
    51export class ContactFormComponent {
    52  form: FormGroup;
    53  submitting = false;
    54  submitted = false;
    55  error = '';
    56
    57  constructor(private fb: FormBuilder, private http: HttpClient) {
    58    this.form = this.fb.group({
    59      name: ['', Validators.required],
    60      email: ['', [Validators.required, Validators.email]],
    61      message: [''],
    62    });
    63  }
    64
    65  get f() {
    66    return this.form.controls;
    67  }
    68
    69  onSubmit() {
    70    if (this.form.invalid) return;
    71
    72    this.submitting = true;
    73    this.error = '';
    74
    75    this.http
    76      .post('https://formboost.app/f/YOUR_ENDPOINT_ID', this.form.value)
    77      .subscribe({
    78        next: () => {
    79          this.submitted = true;
    80          this.submitting = false;
    81        },
    82        error: () => {
    83          this.error = 'Something went wrong. Please try again.';
    84          this.submitting = false;
    85        },
    86      });
    87  }
    88}

    Replace YOUR_ENDPOINT_ID with your Formboost endpoint ID.

    Template-Driven Alternative

    If you prefer template-driven forms:

    1<!-- contact-form.component.html -->
    2<form #contactForm="ngForm" (ngSubmit)="onSubmit(contactForm)">
    3  <div>
    4    <label for="name">Name</label>
    5    <input id="name" name="name" ngModel required #name="ngModel" />
    6    <span *ngIf="name.touched && name.invalid">Name is required</span>
    7  </div>
    8
    9  <div>
    10    <label for="email">Email</label>
    11    <input id="email" name="email" type="email" ngModel required email #email="ngModel" />
    12    <span *ngIf="email.touched && email.errors?.['required']">Email is required</span>
    13    <span *ngIf="email.touched && email.errors?.['email']">Invalid email</span>
    14  </div>
    15
    16  <div>
    17    <label for="message">Message</label>
    18    <textarea id="message" name="message" ngModel rows="5"></textarea>
    19  </div>
    20
    21  <button type="submit" [disabled]="contactForm.invalid">Send</button>
    22</form>
    1onSubmit(form: NgForm) {
    2  this.http
    3    .post('https://formboost.app/f/YOUR_ENDPOINT_ID', form.value)
    4    .subscribe({
    5      next: () => { this.submitted = true; },
    6      error: () => { this.error = 'Something went wrong.'; },
    7    });
    8}

    Validation Summary

    ValidatorUsage
    Validators.requiredField must not be empty
    Validators.emailMust be a valid email format
    Validators.minLength(n)Minimum character count
    Validators.maxLength(n)Maximum character count
    Validators.pattern(regex)Custom regex validation

    Getting Your Endpoint

    1. Sign up at dashboard.formboost.app — free, no credit card
    2. Create a new endpoint and copy the URL
    3. Replace YOUR_ENDPOINT_ID in the component above

    Get your free Formboost endpoint →