diff --git a/packages/fuselage/src/components/PasswordInput/PasswordInput.spec.tsx b/packages/fuselage/src/components/PasswordInput/PasswordInput.spec.tsx
index 8deb7a79bb..6aeee9b8fc 100644
--- a/packages/fuselage/src/components/PasswordInput/PasswordInput.spec.tsx
+++ b/packages/fuselage/src/components/PasswordInput/PasswordInput.spec.tsx
@@ -1,4 +1,5 @@
import { composeStories } from '@storybook/react-webpack5';
+import userEvent from '@testing-library/user-event';
import { axe } from 'jest-axe';
import { render } from '../../testing';
@@ -19,4 +20,28 @@ describe('[PasswordInput Component]', () => {
const results = await axe(container);
expect(results).toHaveNoViolations();
});
+
+ it('toggles password visibility with an accessible button', async () => {
+ const { getByLabelText, getByRole } = render();
+ const input = getByLabelText('password');
+ const toggleButton = getByRole('button', { name: 'Show password' });
+
+ expect(input).toHaveAttribute('type', 'password');
+ expect(toggleButton).toHaveAttribute('aria-pressed', 'false');
+
+ await userEvent.click(toggleButton);
+
+ expect(input).toHaveAttribute('type', 'text');
+ const hideButton = getByRole('button', { name: 'Hide password' });
+ expect(hideButton).toHaveAttribute('aria-pressed', 'true');
+
+ hideButton.focus();
+ await userEvent.keyboard('{Enter}');
+
+ expect(input).toHaveAttribute('type', 'password');
+ expect(getByRole('button', { name: 'Show password' })).toHaveAttribute(
+ 'aria-pressed',
+ 'false',
+ );
+ });
});
diff --git a/packages/fuselage/src/components/PasswordInput/PasswordInput.tsx b/packages/fuselage/src/components/PasswordInput/PasswordInput.tsx
index cd439c4af7..59d4831d5e 100644
--- a/packages/fuselage/src/components/PasswordInput/PasswordInput.tsx
+++ b/packages/fuselage/src/components/PasswordInput/PasswordInput.tsx
@@ -1,30 +1,49 @@
import { useToggle } from '@rocket.chat/fuselage-hooks';
+import type { KeyboardEvent } from 'react';
import { forwardRef } from 'react';
import { Icon } from '../Icon';
import { InputBox, type InputBoxProps } from '../InputBox';
-// TODO: fix a11y issues
-
export type PasswordInputProps = Omit;
const PasswordInput = forwardRef(
- function PasswordInput(props, ref) {
+ function PasswordInput({ disabled, ...props }, ref) {
const [hidden, toggle] = useToggle(true);
const handleAddonClick = () => {
+ if (disabled) {
+ return;
+ }
+
toggle();
};
+ const handleAddonKeyDown = (event: KeyboardEvent) => {
+ if (event.key !== 'Enter' && event.key !== ' ') {
+ return;
+ }
+
+ event.preventDefault();
+ handleAddonClick();
+ };
return (
}
+ disabled={disabled}
ref={ref}
{...props}
/>
diff --git a/packages/fuselage/src/components/PasswordInput/__snapshots__/PasswordInput.spec.tsx.snap b/packages/fuselage/src/components/PasswordInput/__snapshots__/PasswordInput.spec.tsx.snap
index 842816429d..d286e3a31c 100644
--- a/packages/fuselage/src/components/PasswordInput/__snapshots__/PasswordInput.spec.tsx.snap
+++ b/packages/fuselage/src/components/PasswordInput/__snapshots__/PasswordInput.spec.tsx.snap
@@ -16,8 +16,12 @@ exports[`[PasswordInput Component] renders without crashing 1`] = `
class="rcx-box rcx-box--full rcx-input-box__addon"
>