# Overview

TanStack Form is the ultimate solution for handling forms in web applications, providing a powerful and flexible approach to form management. Designed with first-class TypeScript support, headless UI components, and a framework-agnostic design, it streamlines form handling and ensures a seamless experience across various front-end frameworks.

## Motivation

Most web frameworks do not offer a comprehensive solution for form handling, leaving developers to create their own custom implementations or rely on less-capable libraries. This often results in a lack of consistency, poor performance, and increased development time. TanStack Form aims to address these challenges by providing an all-in-one solution for managing forms that is both powerful and easy to use.

With TanStack Form, developers can tackle common form-related challenges such as:

- Reactive data binding and state management
- Complex validation and error handling
- Accessibility and responsive design
- Internationalization and localization
- Cross-platform compatibility and custom styling

By providing a complete solution for these challenges, TanStack Form empowers developers to build robust and user-friendly forms with ease.

## Enough talk, show me some code already!

In the example below, you can see TanStack Form in action with the Angular framework adapter:

[Open in CodeSandbox](https://codesandbox.io/s/github/tanstack/form/tree/alpha/examples/angular/simple)

<!-- ::start:tabs variant="files" -->

```angular-ts title="app.component.ts"
import { ChangeDetectionStrategy, Component } from '@angular/core'
import {
  TanStackField,
  injectForm,
  injectSelector,
} from '@tanstack/angular-form'

@Component({
  selector: 'app-root',
  standalone: true,
  changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [TanStackField],
  template: `
    <main>
      <h1>Simple Form Example</h1>
      <form (submit)="handleSubmit($event)">
        <ng-container
          [tanstackField]="form"
          name="firstName"
          [validators]="firstNameValidators"
          #firstName="field"
        >
          <label [class.validating]="firstName.api.meta.isValidating">
            <span>First Name</span>
            <input
              [name]="firstName.api.name"
              [value]="firstName.api.value"
              (blur)="firstName.api.handleBlur()"
              (input)="firstName.api.handleChange($any($event).target.value)"
              [attr.aria-invalid]="firstName.api.meta.isInvalid"
            />
            @if (firstName.api.meta.isTouched && firstName.api.meta.isInvalid) {
              @for (error of firstName.api.errors; track error) {
                <small role="alert">{{ error.message }}</small>
              }
            }
          </label>
        </ng-container>

        <ng-container [tanstackField]="form" name="lastName" #lastName="field">
          <label>
            <span>Last Name</span>
            <input
              [name]="lastName.api.name"
              [value]="lastName.api.value"
              (blur)="lastName.api.handleBlur()"
              (input)="lastName.api.handleChange($any($event).target.value)"
            />
          </label>
        </ng-container>

        <div class="actions">
          <button type="submit" [disabled]="!canSubmit() || isSubmitting()">
            {{ isSubmitting() ? '...' : 'Submit' }}
          </button>
          <button type="button" (click)="form.reset()">Reset</button>
        </div>
      </form>
    </main>
  `,
})
export class AppComponent {
  firstNameValidators = [
    {
      run: ({ value }: { value: string }) =>
        !value
          ? 'A first name is required'
          : value.length < 3
            ? 'First name must be at least 3 characters'
            : undefined,
      triggers: ['change'] as const,
    },
    {
      run: async ({ value }: { value: string }) => {
        await new Promise((resolve) => setTimeout(resolve, 1000))
        return value.includes('error')
          ? 'No "error" allowed in first name'
          : undefined
      },
      triggers: ['change'] as const,
      triggerDebounceMs: 500,
    },
  ]

  form = injectForm({
    defaultValues: { firstName: '', lastName: '' },
    onSubmit: async ({ value }) => console.log(value),
  })

  canSubmit = injectSelector(this.form, (state) => state.canSubmit)
  isSubmitting = injectSelector(this.form, (state) => state.isSubmitting)

  handleSubmit(event: SubmitEvent) {
    event.preventDefault()
    event.stopPropagation()
    void this.form.handleSubmit()
  }
}
```

<!-- ::end:tabs -->

> Other framework adapters are coming soon and are already supported in the stable version of TanStack Form.

## You talked me into it, so what now?

- Learn TanStack Form at your own pace with our thorough [Walkthrough Guide](./installation) and [API Reference](./reference/interfaces/FormApi).
