Error Encyclopedia

Unsupported binding on a form field

A template binds, or sets as a static attribute, a property that Signal Forms already controls on an element using the [formField] directive. The field state is the single source of truth for properties such as min, max, required, disabled, and readonly. Specifying them in the template conflicts with the field's schema logic.

The error message names the binding. It reads either "Binding to '[min]' is not allowed..." or "Setting the 'required' attribute is not allowed...".

import {Component, signal} from '@angular/core';
import {form, FormField} from '@angular/forms/signals';

@Component({
  selector: 'app-root',
  imports: [FormField],
  template: `
    <!-- NG8022: [min] and [max] are not allowed with [formField]. -->
    <input type="number" [formField]="f.age" [min]="18" [max]="99" />

    <!-- NG8022: the required attribute is not allowed with [formField]. -->
    <input type="text" [formField]="f.name" required />
  `,
})
export class App {
  f = form(signal({age: 20, name: ''}));
}

The same applies to a custom form control when the template binds an input that the field manages, like [max] on a control that declares a max input.

The properties that cannot be used with [formField] include:

  • Values: value, checked (managed directly by the underlying model signal)
  • Validation rules: required, min, max, minLength, maxLength, pattern (as well as native HTML minlength and maxlength)
  • Interactive state: disabled, readonly, hidden
  • Field status and metadata: name, dirty, touched, invalid, errors, pending, disabledReasons (on custom controls, FormField automatically passes these states to the control, so manually binding them conflicts with the framework's automatic wiring)

There are a few exceptions on native elements:

  • min and max are allowed on <input> elements of type date, time, month, week, and datetime-local. On these types the limits are date or time strings like 2026-01-01, which the numeric min() and max() rules can't express.
  • min and max are also allowed when the type is bound dynamically, because the compiler can't tell what type the input has.
  • value is allowed on <input type="radio">, because there it identifies the option. The field value decides which radio button is checked.

Debugging the error

Remove the binding from the template, then handle the property according to its category:

  • Values (value, checked): [formField] automatically binds and two-way synchronizes the element with the underlying model signal. To initialize or change values, update the model signal passed to form().
  • Validation rules (required, min, max, maxLength, etc.): Declare them in the schema function of form() using the corresponding validation rules.
  • Interactive state (disabled, readonly, hidden): Use the schema rules disabled(), readonly(), and hidden(), which also accept an optional when condition, so a rule can depend on other fields. See form logic.
  • Field status and metadata (dirty, touched, errors, etc.): No replacement is needed. [formField] applies them from the field state, and you can read them from the field, for example f.age().dirty().

The example above then becomes:

import {Component, signal} from '@angular/core';
import {disabled, form, FormField, max, maxLength, min, required} from '@angular/forms/signals';

@Component({
  selector: 'app-root',
  imports: [FormField],
  template: `
    <input type="number" [formField]="f.age" />
    <input type="text" [formField]="f.name" />
  `,
})
export class App {
  f = form(signal({age: 20, name: ''}), (p) => {
    min(p.age, 18);
    max(p.age, 99);
    required(p.name);
    maxLength(p.name, 20);
    disabled(p.name, {when: ({valueOf}) => valueOf(p.age) < 18});
  });
}