diff --git a/mon-pix/app/components/authentication/password-checklist/password-checklist-input.gjs b/mon-pix/app/components/authentication/password-checklist/password-checklist-input.gjs
new file mode 100644
index 00000000000..1d7b0d6b758
--- /dev/null
+++ b/mon-pix/app/components/authentication/password-checklist/password-checklist-input.gjs
@@ -0,0 +1,103 @@
+import PixInputPassword from '@1024pix/pix-ui/components/pix-input-password';
+import { on } from '@ember/modifier';
+import { action } from '@ember/object';
+import { service } from '@ember/service';
+import Component from '@glimmer/component';
+import { tracked } from '@glimmer/tracking';
+import { t } from 'ember-intl';
+
+import PasswordChecklist from './password-checklist';
+
+const CONTAINS_UPPERCASE_KEY = 'containsUppercase';
+const CONTAINS_LOWERCASE_KEY = 'containsLowercase';
+const CONTAINS_DIGIT_KEY = 'containsDigit';
+const MIN_LENGTH_KEY = 'minLength';
+
+export default class PasswordChecklistInput extends Component {
+ @service intl;
+
+ @tracked errors = [];
+ @tracked validationStatus = 'default';
+ @tracked value = '';
+
+ get hasValidationStatusError() {
+ return this.validationStatus === 'error';
+ }
+
+ get rules() {
+ return [
+ {
+ key: MIN_LENGTH_KEY,
+ description: this.intl.t('components.authentication.password-checklist.rules.min-length'),
+ },
+ {
+ key: CONTAINS_UPPERCASE_KEY,
+ description: this.intl.t('components.authentication.password-checklist.rules.contains-uppercase'),
+ },
+ {
+ key: CONTAINS_LOWERCASE_KEY,
+ description: this.intl.t('components.authentication.password-checklist.rules.contains-lowercase'),
+ },
+ {
+ key: CONTAINS_DIGIT_KEY,
+ description: this.intl.t('components.authentication.password-checklist.rules.contains-digit'),
+ },
+ ];
+ }
+
+ handleValidation() {
+ const errors = [];
+ const hasDigit = (value) => /\d/.test(value);
+ const hasLowercase = (value) => /[a-z]/.test(value);
+ const hasUppercase = (value) => /[A-Z]/.test(value);
+ const hasMinLength = (value) => value.length && value.length >= 8;
+ const value = this.value;
+
+ if (!hasDigit(value)) errors.push(CONTAINS_DIGIT_KEY);
+ if (!hasLowercase(value)) errors.push(CONTAINS_LOWERCASE_KEY);
+ if (!hasUppercase(value)) errors.push(CONTAINS_UPPERCASE_KEY);
+ if (!hasMinLength(value)) errors.push(MIN_LENGTH_KEY);
+
+ return errors;
+ }
+
+ @action
+ handleUpdatedPassword(event) {
+ this.value = event.target.value;
+ this.errors = this.handleValidation();
+
+ if (this.value && this.errors.length === 0) {
+ this.validationStatus = 'success';
+ }
+
+ if (this.args.onInput) {
+ this.args.onInput(event);
+ }
+ }
+
+ @action
+ checkValidity() {
+ if (!this.value || this.errors.length > 0) {
+ this.validationStatus = 'error';
+ }
+ }
+
+
+
+ <:label>{{t "pages.sign-in.fields.password.label"}}
+
+
+
+
+}
diff --git a/mon-pix/tests/integration/components/authentication/password-checklist/password-checklist-input-test.gjs b/mon-pix/tests/integration/components/authentication/password-checklist/password-checklist-input-test.gjs
new file mode 100644
index 00000000000..df985dce45c
--- /dev/null
+++ b/mon-pix/tests/integration/components/authentication/password-checklist/password-checklist-input-test.gjs
@@ -0,0 +1,122 @@
+import { fillByLabel, render } from '@1024pix/ember-testing-library';
+import { on } from '@ember/modifier';
+import { blur } from '@ember/test-helpers';
+import { t } from 'ember-intl/test-support';
+import PasswordChecklistInput from 'mon-pix/components/authentication/password-checklist/password-checklist-input';
+import { module, test } from 'qunit';
+import sinon from 'sinon';
+
+import setupIntlRenderingTest from '../../../../helpers/setup-intl-rendering';
+
+const I18N = {
+ PASSWORD_INPUT_LABEL: 'pages.sign-in.fields.password.label',
+ RULES_STATUS_MESSAGE: 'components.authentication.password-checklist.rules.completed-message',
+ ERROR_MESSAGE: 'components.authentication.password-checklist.error-message',
+};
+
+module('Integration | Component | authentication | password-checklist-input', function (hooks) {
+ setupIntlRenderingTest(hooks);
+
+ module('password rules', function () {
+ test('it respects all rules', async function (assert) {
+ // given
+ const password = 'Pix12345';
+ const onInput = sinon.spy();
+
+ const screen = await render();
+
+ // when
+ await fillByLabel(t(I18N.PASSWORD_INPUT_LABEL), password);
+ const passwordInputElement = screen.getByLabelText(t(I18N.PASSWORD_INPUT_LABEL));
+ await blur(passwordInputElement);
+
+ // then
+ const onInputEvent = onInput.firstCall.args[0];
+ assert.strictEqual(onInputEvent.target.value, password);
+
+ assert.dom(passwordInputElement).doesNotHaveAttribute('aria-invalid');
+
+ const rulesStatusMessage = t(I18N.RULES_STATUS_MESSAGE, { rulesCompleted: 4, rulesNumber: 4 });
+ assert.dom(screen.getByText(rulesStatusMessage)).exists();
+ });
+
+ test('it does not respect any rules', async function (assert) {
+ // given
+ const password = ' ';
+ const onInput = sinon.stub();
+
+ const screen = await render();
+
+ // when
+ await fillByLabel(t(I18N.PASSWORD_INPUT_LABEL), password);
+ const passwordInputElement = screen.getByLabelText(t(I18N.PASSWORD_INPUT_LABEL));
+ await blur(passwordInputElement);
+
+ // then
+ assert.dom(passwordInputElement).hasAttribute('aria-invalid');
+
+ const rulesStatusMessage = t(I18N.RULES_STATUS_MESSAGE, { rulesCompleted: 0, rulesNumber: 4 });
+ assert.dom(screen.getByText(rulesStatusMessage)).exists();
+ });
+
+ test('it must have a minimum length of 8 chars', async function (assert) {
+ // given
+ const password = 'Pix1234';
+ const onInput = sinon.stub();
+
+ const screen = await render();
+
+ // when
+ await fillByLabel(t(I18N.PASSWORD_INPUT_LABEL), password);
+
+ // then
+ const rulesStatusMessage = t(I18N.RULES_STATUS_MESSAGE, { rulesCompleted: 3, rulesNumber: 4 });
+ assert.dom(screen.getByText(rulesStatusMessage)).exists();
+ });
+
+ test('it must contains at least one uppercase char', async function (assert) {
+ // given
+ const password = 'pix12345';
+ const onInput = sinon.stub();
+
+ const screen = await render();
+
+ // when
+ await fillByLabel(t(I18N.PASSWORD_INPUT_LABEL), password);
+
+ // then
+ const rulesStatusMessage = t(I18N.RULES_STATUS_MESSAGE, { rulesCompleted: 3, rulesNumber: 4 });
+ assert.dom(screen.getByText(rulesStatusMessage)).exists();
+ });
+
+ test('it must contains at least one lowercase char', async function (assert) {
+ // given
+ const password = 'PIX12345';
+ const onInput = sinon.stub();
+
+ const screen = await render();
+
+ // when
+ await fillByLabel(t(I18N.PASSWORD_INPUT_LABEL), password);
+
+ // then
+ const rulesStatusMessage = t(I18N.RULES_STATUS_MESSAGE, { rulesCompleted: 3, rulesNumber: 4 });
+ assert.dom(screen.getByText(rulesStatusMessage)).exists();
+ });
+
+ test('it must contains at least one digit', async function (assert) {
+ // given
+ const password = 'PIXpixPIX';
+ const onInput = sinon.stub();
+
+ const screen = await render();
+
+ // when
+ await fillByLabel(t(I18N.PASSWORD_INPUT_LABEL), password);
+
+ // then
+ const rulesStatusMessage = t(I18N.RULES_STATUS_MESSAGE, { rulesCompleted: 3, rulesNumber: 4 });
+ assert.dom(screen.getByText(rulesStatusMessage)).exists();
+ });
+ });
+});