From 20f3aebf5c8e62e68f96dc808db10f4f8b61ed26 Mon Sep 17 00:00:00 2001 From: Modeste ASSIONGBON Date: Fri, 13 Mar 2026 00:46:40 +0100 Subject: [PATCH 1/3] docs: add doc to focusBoundControl feature --- .../forms/signals/focus-bound-control.md | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 adev/src/content/guide/forms/signals/focus-bound-control.md diff --git a/adev/src/content/guide/forms/signals/focus-bound-control.md b/adev/src/content/guide/forms/signals/focus-bound-control.md new file mode 100644 index 000000000000..204889543e09 --- /dev/null +++ b/adev/src/content/guide/forms/signals/focus-bound-control.md @@ -0,0 +1,78 @@ +# Focusing a bound form control + +Angular Signal Forms provide a `focusBoundControl()` method on field state that lets you programmatically move 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, pass `{ preventScroll: true }`: + +```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 with separate day, month, and year fields), 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 +
+ +
+``` + +```ts +@Component({/* ... */}) +export class PasswordInput implements FormValueControl { + readonly value = model(''); + readonly passwordCtrl = viewChild.required('passwordCtrl'); + + // Called automatically when focusBoundControl() is invoked + // on the field state associated with this custom control + focus(): void { + (this.passwordCtrl().nativeElement as HTMLInputElement).focus(); + } +} +``` From c15107a6aaa0a178044a7a84ce10eff41736bb82 Mon Sep 17 00:00:00 2001 From: Modeste ASSIONGBON Date: Fri, 13 Mar 2026 08:23:03 +0100 Subject: [PATCH 2/3] docs: focusBoundControl - add links to MDN, move doc as section of existing field state doc --- .../forms/signals/field-state-management.md | 83 +++++++++++++++++++ .../forms/signals/focus-bound-control.md | 78 ----------------- 2 files changed, 83 insertions(+), 78 deletions(-) delete mode 100644 adev/src/content/guide/forms/signals/focus-bound-control.md 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..84e3926ce53a 100644 --- a/adev/src/content/guide/forms/signals/field-state-management.md +++ b/adev/src/content/guide/forms/signals/field-state-management.md @@ -721,10 +721,93 @@ 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 with separate day, month, and year fields), 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 +
+ +
+``` + +```ts +@Component({/* ... */}) +export class PasswordInput implements FormValueControl { + readonly value = model(''); + readonly passwordCtrl = viewChild.required>('passwordCtrl'); + + // Called automatically when focusBoundControl() is invoked + // on the field state associated with this custom control + focus(): void { + this.passwordCtrl().nativeElement.focus(); + } +} +``` + + ## Next steps This guide covered validation and availability status handling, interaction tracking and field state propagation. Related guides explore other aspects of Signal Forms: + + diff --git a/adev/src/content/guide/forms/signals/focus-bound-control.md b/adev/src/content/guide/forms/signals/focus-bound-control.md deleted file mode 100644 index 204889543e09..000000000000 --- a/adev/src/content/guide/forms/signals/focus-bound-control.md +++ /dev/null @@ -1,78 +0,0 @@ -# Focusing a bound form control - -Angular Signal Forms provide a `focusBoundControl()` method on field state that lets you programmatically move 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, pass `{ preventScroll: true }`: - -```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 with separate day, month, and year fields), 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 -
- -
-``` - -```ts -@Component({/* ... */}) -export class PasswordInput implements FormValueControl { - readonly value = model(''); - readonly passwordCtrl = viewChild.required('passwordCtrl'); - - // Called automatically when focusBoundControl() is invoked - // on the field state associated with this custom control - focus(): void { - (this.passwordCtrl().nativeElement as HTMLInputElement).focus(); - } -} -``` From 6f496f896923f2a0d52ae664d302bea4ecb9e985 Mon Sep 17 00:00:00 2001 From: Modeste ASSIONGBON Date: Fri, 13 Mar 2026 16:51:27 +0100 Subject: [PATCH 3/3] docs: fix line breaks inconsistency, apply review suggestion --- .../content/guide/forms/signals/field-state-management.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) 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 84e3926ce53a..3a4eae5f6ffb 100644 --- a/adev/src/content/guide/forms/signals/field-state-management.md +++ b/adev/src/content/guide/forms/signals/field-state-management.md @@ -722,6 +722,7 @@ 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. @@ -752,12 +753,10 @@ registrationForm.email().focusBoundControl(); 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: @@ -775,7 +774,7 @@ onSubmit() { ### 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 with separate day, month, and year fields), Angular cannot determine which element should receive focus or what action to perform. +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. @@ -801,13 +800,10 @@ export class PasswordInput implements FormValueControl { } ``` - ## Next steps This guide covered validation and availability status handling, interaction tracking and field state propagation. Related guides explore other aspects of Signal Forms: - -