diff --git a/core/src/components/button/button.tsx b/core/src/components/button/button.tsx index 4e63b8413ea..47326abfea8 100644 --- a/core/src/components/button/button.tsx +++ b/core/src/components/button/button.tsx @@ -1,5 +1,5 @@ import type { ComponentInterface, EventEmitter } from '@stencil/core'; -import { Component, Element, Event, Host, Prop, Watch, State, h } from '@stencil/core'; +import { Component, Element, Event, Host, Prop, Watch, State, forceUpdate, h } from '@stencil/core'; import type { AnchorInterface, ButtonInterface } from '@utils/element-interface'; import type { Attributes } from '@utils/helpers'; import { inheritAriaAttributes, hasShadowDom } from '@utils/helpers'; @@ -158,6 +158,26 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf */ @Event() ionBlur!: EventEmitter; + /** + * This component is used within the `ion-input-password-toggle` component + * to toggle the visibility of the password input. + * These attributes need to update based on the state of the password input. + * Otherwise, the values will be stale. + * + * @param newValue + * @param _oldValue + * @param propName + */ + @Watch('aria-checked') + @Watch('aria-label') + onAriaChanged(newValue: string, _oldValue: string, propName: string) { + this.inheritedAttributes = { + ...this.inheritedAttributes, + [propName]: newValue, + }; + forceUpdate(this); + } + /** * This is responsible for rendering a hidden native * button element inside the associated form. This allows diff --git a/core/src/components/input-password-toggle/input-password-toggle.tsx b/core/src/components/input-password-toggle/input-password-toggle.tsx index 44b8e0828a1..90b743b41e7 100644 --- a/core/src/components/input-password-toggle/input-password-toggle.tsx +++ b/core/src/components/input-password-toggle/input-password-toggle.tsx @@ -127,7 +127,7 @@ export class InputPasswordToggle implements ComponentInterface { fill="clear" shape="round" aria-checked={isPasswordVisible ? 'true' : 'false'} - aria-label="show password" + aria-label={isPasswordVisible ? 'Hide password' : 'Show password'} role="switch" type="button" onPointerDown={(ev) => { diff --git a/core/src/components/input-password-toggle/test/a11y/input-password-toggle.e2e.ts b/core/src/components/input-password-toggle/test/a11y/input-password-toggle.e2e.ts index 76b9f3d2837..0493509dc24 100644 --- a/core/src/components/input-password-toggle/test/a11y/input-password-toggle.e2e.ts +++ b/core/src/components/input-password-toggle/test/a11y/input-password-toggle.e2e.ts @@ -20,4 +20,38 @@ configs({ directions: ['ltr'] }).forEach(({ title, config }) => { expect(results.violations).toEqual([]); }); }); + + test.describe(title('input password toggle: aria attributes'), () => { + test('should inherit aria attributes to inner button on load', async ({ page }) => { + await page.setContent( + ` + + + + `, + config + ); + + const nativeButton = page.locator('ion-input-password-toggle button'); + + await expect(nativeButton).toHaveAttribute('aria-label', 'Show password'); + await expect(nativeButton).toHaveAttribute('aria-checked', 'false'); + }); + test('should inherit aria attributes to inner button after toggle', async ({ page }) => { + await page.setContent( + ` + + + + `, + config + ); + + const nativeButton = page.locator('ion-input-password-toggle button'); + await nativeButton.click(); + + await expect(nativeButton).toHaveAttribute('aria-label', 'Hide password'); + await expect(nativeButton).toHaveAttribute('aria-checked', 'true'); + }); + }); });