splitforms.com

Contact form · Angular

Angular contact form with Reactive Forms & HttpClient

Reactive Forms give you typed, synchronous validation; HttpClient gives you a typed Observable POST. Wire them to the splitforms endpoint and ship a contact form with no service, no controller, and no backend. Standalone component, Angular 17+ — works in NgModule apps too.

  • 500 free / mo
  • 14ms latency
  • No backend code
Angular contact form — copy-paste code for splitforms

No backend code

No server, API route, or SDK. Your Angular form posts straight to one endpoint.

Straight to your inbox

Every submission is emailed to you and saved to a searchable dashboard — spam filtered before it reaches you.

Design without limits

It's your own Angular markup and styles. Splitforms is only the backend, so nothing constrains how the form looks.

Copy-paste ready

Your Angular contact form, ready to paste.

Replace YOUR_ACCESS_KEY with the key from your dashboard — that's the whole integration. No SDK to install, no build step, just the typescript you already write.

Generate access key
contact.html
// contact-form.component.ts — Angular 17+ standalone component
import { Component, inject, signal } from "@angular/core";
import { CommonModule } from "@angular/common";
import { ReactiveFormsModule, FormBuilder, Validators } from "@angular/forms";
import { HttpClient } from "@angular/common/http";

@Component({
  selector: "app-contact-form",
  standalone: true,
  imports: [CommonModule, ReactiveFormsModule],
  template: `
    <form [formGroup]="form" (ngSubmit)="submit()">
      <input type="hidden" formControlName="access_key" />

      <label>
        Name
        <input type="text" formControlName="name" />
        <small *ngIf="form.controls.name.touched && form.controls.name.invalid">
          Name is required.
        </small>
      </label>

      <label>
        Email
        <input type="email" formControlName="email" />
        <small *ngIf="form.controls.email.touched && form.controls.email.invalid">
          A valid email is required.
        </small>
      </label>

      <label>
        Message
        <textarea formControlName="message"></textarea>
        <small *ngIf="form.controls.message.touched && form.controls.message.invalid">
          Please add a message.
        </small>
      </label>

      <!-- Honeypot — invisible to humans -->
      <input type="checkbox" formControlName="botcheck" hidden tabindex="-1" />

      <button type="submit" [disabled]="status() === 'loading'">
        {{ status() === 'loading' ? 'Sending…' : 'Send' }}
      </button>

      <p *ngIf="status() === 'ok'">Thanks — we'll be in touch.</p>
      <p *ngIf="status() === 'err'">Something went wrong. Try again?</p>
    </form>
  `,
})
export class ContactFormComponent {
  private fb = inject(FormBuilder);
  private http = inject(HttpClient);

  status = signal<"idle" | "loading" | "ok" | "err">("idle");

  form = this.fb.group({
    access_key: ["YOUR_ACCESS_KEY"],
    name: ["", Validators.required],
    email: ["", [Validators.required, Validators.email]],
    message: ["", Validators.required],
    botcheck: [false],
  });

  submit() {
    if (this.form.invalid) {
      this.form.markAllAsTouched();
      return;
    }
    this.status.set("loading");

    // Build a real multipart FormData so file fields (if you add them) work too.
    const fd = new FormData();
    Object.entries(this.form.getRawValue()).forEach(([k, v]) =>
      fd.append(k, String(v))
    );

    this.http
      .post<{ success: boolean; message?: string }>(
        "https://splitforms.com/api/submit",
        fd
      )
      .subscribe({
        next: (data) => {
          this.status.set(data.success ? "ok" : "err");
          if (data.success) this.form.reset({ access_key: "YOUR_ACCESS_KEY" });
        },
        error: () => this.status.set("err"),
      });
  }
}

How to add it

How to add a contact form to a Angular website.

To add a contact form to a Angular website you need three things: a free splitforms access key, the typescript snippet above, and your key pasted into it. No backend, server, or SDK — the form posts to one URL and every submission lands in your inbox and dashboard.

Get your free splitforms access key

Sign up at splitforms.com, verify your email, and copy your access key from the dashboard. No credit card required.

Drop the Angular snippet into your project

Copy the Angular code example into your project and replace YOUR_ACCESS_KEY with the key from step 1.

Receive submissions in your dashboard

Submissions arrive in the splitforms dashboard within seconds. Free includes inbox delivery; Pro adds Slack, Discord, Sheets, or any signed webhook URL.

Where submissions go

Where do your Angular form submissions go?

Every submission is emailed to you and saved to a searchable dashboard — spam filtered before it ever reaches you. Search, export to CSV, or forward it to a webhook or Slack on Pro.

  • 500 submissions per month, free forever
  • Honeypot + AI spam classifier on every plan
  • Signed webhooks to Slack, Discord, your server
Angular contact form submissions in the splitforms dashboard

No backend needed

Do you need a backend for a Angular form? No.

Your Angular form posts standard FormData to one URL. Splitforms validates the access key, runs the spam classifier, and forwards it to your email — so there's no server, API route, or database for you to build or maintain.

  • Reactive Forms with typed FormBuilder + Validators — no template-driven ngModel
  • Standalone component (Angular 17+) — zero NgModule wiring required
  • HttpClient POST returns a typed Observable; cancelable via takeUntilDestroyed
How splitforms processes a Angular form submission

Best practices

What a production-ready Angular form needs.

The difference between a form that works in the demo and one that survives launch traffic — the production-tested defaults, in priority order.

  • Use Reactive Forms (FormBuilder + formControlName), not template-driven ngModel. Reactive forms are synchronous, fully typed, unit-testable, and scale to cross-field validators.
  • Pull the access key from an environment file (environment.splitformsKey) or an InjectionToken — not a hardcoded literal in the component, which gets minified into the client bundle.
  • Build the body with new FormData() and append each control's value. Don't POST form.value as JSON — splitforms expects multipart/form-data.
Production-ready Angular contact form best practices

How SplitForms works

From form to workflow in 3 simple steps.

Connect your form, collect every submission, and send data where it needs to go — without building backend infrastructure.

A SplitForms contact form submission launching straight to your inbox

Add your endpoint

Point your form to your unique SplitForms endpoint. That's it.

HTML form pointing at a SplitForms submit endpoint

Receive submissions

We instantly capture and organize every submission in your inbox.

Submissions inbox with searchable leads and status pills

Route anywhere

Send data to email, spreadsheets, CRMs, webhooks, and 7,000+ apps.

Generic integration tiles for email, sheets, chat, CRM, automate, and webhook

No credit card required. Set up in under 60 seconds.

Connect & automate

Connect your favorite tools and automate everything

SplitForms works with the destinations you route to and the platforms you build on — from Slack and Sheets to WordPress, Shopify, and Next.js.

Connect your SplitForms form to Slack, Google Sheets, Mailchimp, Zapier and more

Trusted by indie teams and agencies shipping forms worldwide

PETAL/COKRAFT.DELINEAR-XBUILD.DEVSTUDIO 71MERIDIANFRAME&CO

Testimonials

Loved by developers shipping at every scale.

40 quotes on record — from indie hacks to agency migrations.

Questions

Angular contact form questions.

View all FAQs
How do I submit an Angular Reactive Form to splitforms?

Build a FormGroup with FormBuilder, then on (ngSubmit) append each control's value (plus access_key) to a FormData and call httpClient.post('https://splitforms.com/api/submit', fd).subscribe(…). Inspect data.success in next; handle 4xx in error.

Should I use Reactive Forms or template-driven forms?

Reactive Forms (FormBuilder, formControlName). They're synchronous, fully typed, unit-testable, and scale to cross-field validators. Template-driven forms with ngModel work for tiny forms but get unwieldy and harder to test. splitforms is form-agnostic — it only cares about the multipart body.

How do I handle errors with HttpClient?

HttpClient routes any non-2xx response to the error callback of .subscribe({ next, error }) (or to catchError in the pipe). Inspect err.error?.message for splitforms' user-facing message. 2xx responses with success: false (e.g. spam flagged) still arrive in next — always check data.success there too.

Does splitforms work with standalone components and Angular 17/18/19?

Yes. The component above is standalone (standalone: true, imports ReactiveFormsModule). No NgModule changes. If you're on a NgModule-based app, just declare the component and provide HttpClient once via provideHttpClient() (or import HttpClientModule) in your app config.

How do I keep the access key out of the bundle?

You can't fully — Angular compiles to client-side JavaScript, so anything the component reads ends up in the bundle. The right mitigation is domain-locking the key in the splitforms dashboard (Settings → Allowed domains). For true server-side secrecy, proxy through an Angular Universal server route that injects the key from process.env server-side.

Can I use this with Angular Universal (SSR)?

Yes, but POST from the browser, not during server rendering. Guard the HttpClient call with isPlatformBrowser(platformId) or keep it inside the (ngSubmit) handler (which only fires client-side). The form markup can render on the server; the submission must originate from the browser.

Never set Content-Type yourself when the body is FormData

Angular's HttpClient inspects the body argument: pass a FormData instance and it sets Content-Type: multipart/form-data; boundary=… automatically. If you manually add a Content-Type: multipart/form-data header in the options (a common copy-paste from older AngularJS tutorials), Angular doesn't know the boundary string and the request body can't be parsed — splitforms returns 400 malformed body. Same rule as fetch and jQuery: leave the header alone when the body is FormData.

HttpClient routes 4xx/5xx to the error callback — not to next

Unlike fetch, Angular's HttpClient treats any non-2xx status as an error and routes it to the error callback of .subscribe({ next, error }) (or to catchError in the pipe). That means splitforms' 4xx responses (invalid key, spam flagged, rate-limit) hit error, NOT next — so data.success is never checked for those cases and you'll miss the user-facing message entirely. Read err.error?.message in the error handler, or normalize both paths with catchError. Remember: 2xx with success: false still lands in next, so check data.success there too.

Validation errors don't render until a control is touched or dirty

Bootstrap-style 'show errors after submit' isn't automatic in Angular — a control's errors are present in form.controls.email.invalid but the *ngIf template guard usually checks .touched too, so nothing displays until the user blurs the field. In submit(), call this.form.markAllAsTouched() before returning early on this.form.invalid, or users click Send on an empty form and see nothing happen. Also prefer the strict this.fb.group over fb.group (pre-14) which returned FormGroup<any> and let typos like form.controls.emial compile.

Simple pricing

Start free. Scale when you need more.

Choose a plan that fits your workflow — from a free form endpoint to full automations, exports, and higher submission limits.

Free

$0

Free forever

 
Best for testing

For side projects and indie devs.

  • 500 submissions / mo
  • Unlimited forms
  • Email notifications included
  • Honeypot spam filtering
  • Submissions dashboard
  • MCP setup stays free
  • No credit card required

3-Year

$59/ 36 months
was $99 · save 40% · new-user price

Pay $59. 3 years sorted.

  • 15,000 submissions / mo
  • Unlimited forms
  • Everything in Pro
  • Renews every 3 years
  • Long-term discount
  • Priority support included
  • Vote on the roadmap

No credit card required on Free • Cancel anytime