diff --git a/libs/components/src/form-field/form-field.stories.ts b/libs/components/src/form-field/form-field.stories.ts index f5bb04bff0f..dae747b0395 100644 --- a/libs/components/src/form-field/form-field.stories.ts +++ b/libs/components/src/form-field/form-field.stories.ts @@ -10,6 +10,7 @@ import { } from "@angular/forms"; import { Meta, StoryObj, moduleMetadata } from "@storybook/angular"; +import { A11yTitleDirective } from "@bitwarden/angular/src/directives/a11y-title.directive"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { AsyncActionsModule } from "../async-actions"; @@ -50,6 +51,7 @@ export default { TextFieldModule, BadgeModule, ], + declarations: [A11yTitleDirective], providers: [ { provide: I18nService, @@ -237,7 +239,7 @@ export const Readonly: Story = { Input - + @@ -258,7 +260,7 @@ export const Readonly: Story = { Input - + @@ -302,14 +304,14 @@ export const ButtonInputGroup: Story = { Label - + - + - - + + @@ -325,10 +327,10 @@ export const DisabledButtonInputGroup: Story = { template: /*html*/ ` Label - + - - + + @@ -345,8 +347,8 @@ export const PartiallyDisabledButtonInputGroup: Story = { Label - - + + diff --git a/libs/components/src/form-field/prefix.directive.ts b/libs/components/src/form-field/prefix.directive.ts index bcfc9d01fe4..34fcbf85233 100644 --- a/libs/components/src/form-field/prefix.directive.ts +++ b/libs/components/src/form-field/prefix.directive.ts @@ -1,34 +1,20 @@ -import { AfterContentInit, Directive, HostBinding, Input, OnInit, Optional } from "@angular/core"; +import { Directive, HostBinding, Input, OnInit, Optional } from "@angular/core"; import { BitIconButtonComponent } from "../icon-button/icon-button.component"; -import { BitFormFieldComponent } from "./form-field.component"; - @Directive({ selector: "[bitPrefix]", }) -export class BitPrefixDirective implements OnInit, AfterContentInit { +export class BitPrefixDirective implements OnInit { @HostBinding("class") @Input() get classList() { return ["tw-text-muted"]; } - @HostBinding("attr.aria-describedby") - protected ariaDescribedBy: string; - - constructor( - @Optional() private parentFormField: BitFormFieldComponent, - @Optional() private iconButtonComponent: BitIconButtonComponent, - ) {} + constructor(@Optional() private iconButtonComponent: BitIconButtonComponent) {} ngOnInit() { if (this.iconButtonComponent) { this.iconButtonComponent.size = "small"; } } - - ngAfterContentInit() { - if (this.parentFormField?.label?.id) { - this.ariaDescribedBy = this.parentFormField.label.id; - } - } } diff --git a/libs/components/src/form-field/suffix.directive.ts b/libs/components/src/form-field/suffix.directive.ts index 39fcce916cc..28736ce78a9 100644 --- a/libs/components/src/form-field/suffix.directive.ts +++ b/libs/components/src/form-field/suffix.directive.ts @@ -1,34 +1,20 @@ -import { AfterContentInit, Directive, HostBinding, Input, OnInit, Optional } from "@angular/core"; +import { Directive, HostBinding, Input, OnInit, Optional } from "@angular/core"; import { BitIconButtonComponent } from "../icon-button/icon-button.component"; -import { BitFormFieldComponent } from "./form-field.component"; - @Directive({ selector: "[bitSuffix]", }) -export class BitSuffixDirective implements OnInit, AfterContentInit { +export class BitSuffixDirective implements OnInit { @HostBinding("class") @Input() get classList() { return ["tw-text-muted"]; } - @HostBinding("attr.aria-describedby") - protected ariaDescribedBy: string; - - constructor( - @Optional() private parentFormField: BitFormFieldComponent, - @Optional() private iconButtonComponent: BitIconButtonComponent, - ) {} + constructor(@Optional() private iconButtonComponent: BitIconButtonComponent) {} ngOnInit() { if (this.iconButtonComponent) { this.iconButtonComponent.size = "small"; } } - - ngAfterContentInit() { - if (this.parentFormField?.label?.id) { - this.ariaDescribedBy = this.parentFormField.label.id; - } - } } diff --git a/libs/components/src/form/forms.mdx b/libs/components/src/form/forms.mdx index 5ce129bf301..fbb3a20e518 100644 --- a/libs/components/src/form/forms.mdx +++ b/libs/components/src/form/forms.mdx @@ -152,6 +152,12 @@ If a checkbox group has more than 4 options a helper text. - **Example:** "Billing Email is required if owned by a business". +### Icon Buttons in Form Fields + +When adding prefix or suffix icon buttons to a form field, be sure to use the `appA11yTitle` +directive to provide a label for screenreaders. Typically, the label should follow this pattern: +`{Action} {field label}`, i.e. "Copy username". + ### Form Field Errors - When a resting field is filled out, validation is triggered when the user de-focuses the field