diff --git a/adev/src/content/guide/forms/signals/field-state-management.md b/adev/src/content/guide/forms/signals/field-state-management.md index 82b74aa00042..3a4eae5f6ffb 100644 --- a/adev/src/content/guide/forms/signals/field-state-management.md +++ b/adev/src/content/guide/forms/signals/field-state-management.md @@ -721,6 +721,85 @@ export class StyleExample { Checking both `touched()` and validation state ensures styles only appear after the user has interacted with the field. +## Focus a form control bound to a form field + +Angular Signal Forms provide a `focusBoundControl()` method on field state that lets you programmatically move [focus](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus) to the form control associated with a given form field. + +A common use case is improving accessibility on form submission: when a form is invalid, display error messages and automatically move focus to the first invalid field, guiding the user to correct it. + +### Basic usage + +Given a registration form: + +```ts +@Component({/* ... */}) +export class Registration { + registrationModel = signal({ username: '', email: '', password: '' }); + registrationForm = form(this.registrationModel, (schemaPath) => { + required(schemaPath.username); + email(schemaPath.email); + required(schemaPath.password); + }); +} +``` + +To move focus to the control bound to the `email` field: + +```ts +registrationForm.email().focusBoundControl(); +``` + +### Preventing scroll + +If the target control is outside the viewport and you want to focus it without triggering a scroll, you can set the [preventScroll](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus#preventscroll) option to `true` when calling the `focusBoundControl()` method. + +```ts +registrationForm.email().focusBoundControl({ preventScroll: true }); +``` + +### Focusing the first invalid field on submission + +Use `errorSummary()` to locate the first invalid field and focus it when the user submits the form with errors: + +```ts +onSubmit() { + const firstError = this.registrationForm().errorSummary()[0]; + if (firstError?.fieldTree) { + firstError.fieldTree().focusBoundControl(); + } else { + // proceed with submission + } +} +``` + +### Custom controls + +By default, calling `focusBoundControl()` on a custom control has no effect because a custom control can contain multiple native inputs. For example, a date picker can contain separate day, month, and year fields. As a result, Angular cannot determine which element should receive focus or what action to perform. + +To support programmatic focus in a custom control, implement a `focus()` method. When `focusBoundControl()` is called on the field state associated with a custom control, Angular calls the control's `focus()` method if one is present. + +Consider a custom password input: + +```html +