diff --git a/components/brave_account/resources/BUILD.gn b/components/brave_account/resources/BUILD.gn
index 2994cc1c85d..d249bebdfc0 100644
--- a/components/brave_account/resources/BUILD.gn
+++ b/components/brave_account/resources/BUILD.gn
@@ -32,6 +32,8 @@ build_webui("build") {
"brave_account_forgot_password_dialog.ts",
"brave_account_password_icons.html.ts",
"brave_account_password_icons.ts",
+ "brave_account_password_strength_meter.html.ts",
+ "brave_account_password_strength_meter.ts",
"brave_account_sign_in_dialog.html.ts",
"brave_account_sign_in_dialog.ts",
]
@@ -44,6 +46,7 @@ build_webui("build") {
"brave_account_entry_dialog.css",
"brave_account_forgot_password_dialog.css",
"brave_account_password_icons.css",
+ "brave_account_password_strength_meter.css",
"brave_account_sign_in_dialog.css",
]
diff --git a/components/brave_account/resources/brave_account_create_dialog.html.ts b/components/brave_account/resources/brave_account_create_dialog.html.ts
index 2df634db6fa..4ecfdd4df4c 100644
--- a/components/brave_account/resources/brave_account_create_dialog.html.ts
+++ b/components/brave_account/resources/brave_account_create_dialog.html.ts
@@ -7,9 +7,11 @@ import { html } from '//resources/lit/v3_0/lit.rollup.js'
import './brave_account_email_input.js'
import './brave_account_password_icons.js'
+import './brave_account_password_strength_meter.js'
import { BraveAccountCreateDialogElement } from './brave_account_create_dialog.js'
import type { EmailInputEventDetail } from './brave_account_email_input.js'
import { onToggleVisibility } from './brave_account_common.js'
+import type { PasswordStrengthChangedEventDetail } from './brave_account_password_strength_meter.js'
export function getHtml(this: BraveAccountCreateDialogElement) {
return html`
@@ -47,11 +49,18 @@ export function getHtml(this: BraveAccountCreateDialogElement) {
-
-
+
,
+ ) => {
+ this.isPasswordStrongEnough = e.detail.isStrongEnough
+ }}
+ >
+
@@ -101,7 +110,7 @@ export function getHtml(this: BraveAccountCreateDialogElement) {
diff --git a/components/brave_account/resources/brave_account_create_dialog.ts b/components/brave_account/resources/brave_account_create_dialog.ts
index 3e0e831d442..ce5658908c2 100644
--- a/components/brave_account/resources/brave_account_create_dialog.ts
+++ b/components/brave_account/resources/brave_account_create_dialog.ts
@@ -3,14 +3,12 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */
-import { CrLitElement, css, html } from '//resources/lit/v3_0/lit.rollup.js'
-import { loadTimeData } from '//resources/js/load_time_data.js'
+import { CrLitElement } from '//resources/lit/v3_0/lit.rollup.js'
import {
BraveAccountBrowserProxy,
BraveAccountBrowserProxyImpl,
} from './brave_account_browser_proxy.js'
-import { BraveAccountStrings } from './brave_components_webui_strings.js'
import { getCss } from './brave_account_create_dialog.css.js'
import { getHtml } from './brave_account_create_dialog.html.js'
import { Error, makeFocusHandler } from './brave_account_common.js'
@@ -22,106 +20,6 @@ import {
// @ts-expect-error
import { Registration } from 'chrome://resources/brave/opaque_ke.bundle.js'
-class PasswordStrengthMeter extends CrLitElement {
- static get is() {
- return 'password-strength-meter'
- }
-
- static override get styles() {
- return css`
- :host {
- align-items: center;
- display: flex;
- gap: var(--leo-spacing-m);
- justify-content: space-between;
- width: 100%;
- }
-
- :host([category='Weak']) {
- --primary-color: var(--leo-color-systemfeedback-error-icon);
- --secondary-color: var(--leo-color-systemfeedback-error-background);
- }
-
- :host([category='Medium']) {
- --primary-color: var(--leo-color-systemfeedback-warning-icon);
- --secondary-color: var(--leo-color-systemfeedback-warning-background);
- }
-
- :host([category='Strong']) {
- --primary-color: var(--leo-color-systemfeedback-success-icon);
- --secondary-color: var(--leo-color-systemfeedback-success-background);
- }
-
- .bar {
- background-color: var(--secondary-color);
- border-radius: var(--leo-radius-m);
- flex-grow: 1;
- height: 4px;
- transition: 750ms;
- }
-
- .strength {
- background-color: var(--primary-color);
- border-radius: var(--leo-radius-m);
- height: 100%;
- transition: 750ms;
- width: calc(1% * var(--strength));
- }
-
- .text {
- color: var(--primary-color);
- font: var(--leo-font-small-regular);
- transition: 750ms;
- }
- `
- }
-
- override render() {
- return html`
-
-
- ${loadTimeData.getString(
- this.category === 'Weak'
- ? BraveAccountStrings.BRAVE_ACCOUNT_PASSWORD_STRENGTH_METER_WEAK
- : this.category === 'Medium'
- ? BraveAccountStrings.BRAVE_ACCOUNT_PASSWORD_STRENGTH_METER_MEDIUM
- : BraveAccountStrings.BRAVE_ACCOUNT_PASSWORD_STRENGTH_METER_STRONG,
- )}
-
- `
- }
-
- static override get properties() {
- return {
- category: { type: String, reflect: true },
- strength: { type: Number },
- }
- }
-
- override updated(changedProperties: Map) {
- if (changedProperties.has('strength')) {
- this.category =
- this.strength < 60 ? 'Weak' : this.strength < 100 ? 'Medium' : 'Strong'
- }
- }
-
- protected accessor category: 'Weak' | 'Medium' | 'Strong' = 'Weak'
- protected accessor strength: number = 0
-}
-
-declare global {
- interface HTMLElementTagNameMap {
- 'password-strength-meter': PasswordStrengthMeter
- }
-}
-
-customElements.define(PasswordStrengthMeter.is, PasswordStrengthMeter)
-
export class BraveAccountCreateDialogElement extends CrLitElement {
static get is() {
return 'brave-account-create-dialog'
@@ -142,20 +40,14 @@ export class BraveAccountCreateDialogElement extends CrLitElement {
isEmailValid: { type: Boolean },
isPasswordInputFocused: { type: Boolean },
isPasswordConfirmationInputFocused: { type: Boolean },
+ isPasswordStrongEnough: { type: Boolean },
password: { type: String },
passwordConfirmation: { type: String },
- passwordStrength: { type: Number },
}
}
protected onPasswordInput(detail: { value: string }) {
this.password = detail.value
- this.browserProxy.password_strength_meter
- .getPasswordStrength(this.password)
- .then(
- (value: { strength: number }) =>
- (this.passwordStrength = value.strength),
- )
}
protected onPasswordConfirmationInput(detail: { value: string }) {
@@ -232,9 +124,9 @@ export class BraveAccountCreateDialogElement extends CrLitElement {
protected accessor isEmailValid: boolean = false
protected accessor isPasswordInputFocused: boolean = false
protected accessor isPasswordConfirmationInputFocused: boolean = false
+ protected accessor isPasswordStrongEnough: boolean = false
protected accessor password: string = ''
protected accessor passwordConfirmation: string = ''
- protected accessor passwordStrength: number = 0
protected registration = new Registration()
protected readonly passwordFocusHandler = makeFocusHandler(
diff --git a/components/brave_account/resources/brave_account_password_strength_meter.css b/components/brave_account/resources/brave_account_password_strength_meter.css
new file mode 100644
index 00000000000..5e1c2160e52
--- /dev/null
+++ b/components/brave_account/resources/brave_account_password_strength_meter.css
@@ -0,0 +1,53 @@
+/* Copyright (c) 2026 The Brave Authors. All rights reserved.
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+/* #css_wrapper_metadata_start
+ * #type=style-lit
+ * #css_wrapper_metadata_end */
+
+:host {
+ align-items: center;
+ display: flex;
+ gap: var(--leo-spacing-m);
+ justify-content: space-between;
+ width: 100%;
+}
+
+:host([category='Weak']) {
+ --primary-color: var(--leo-color-systemfeedback-error-icon);
+ --secondary-color: var(--leo-color-systemfeedback-error-background);
+}
+
+:host([category='Medium']) {
+ --primary-color: var(--leo-color-systemfeedback-warning-icon);
+ --secondary-color: var(--leo-color-systemfeedback-warning-background);
+}
+
+:host([category='Strong']) {
+ --primary-color: var(--leo-color-systemfeedback-success-icon);
+ --secondary-color: var(--leo-color-systemfeedback-success-background);
+}
+
+.bar {
+ background-color: var(--secondary-color);
+ border-radius: var(--leo-radius-m);
+ flex-grow: 1;
+ height: 4px;
+ transition: 750ms;
+}
+
+.strength {
+ background-color: var(--primary-color);
+ border-radius: var(--leo-radius-m);
+ height: 100%;
+ transition: 750ms;
+ width: calc(1% * var(--strength));
+}
+
+.text {
+ color: var(--primary-color);
+ font: var(--leo-font-small-regular);
+ transition: 750ms;
+}
diff --git a/components/brave_account/resources/brave_account_password_strength_meter.html.ts b/components/brave_account/resources/brave_account_password_strength_meter.html.ts
new file mode 100644
index 00000000000..9686c0a1d18
--- /dev/null
+++ b/components/brave_account/resources/brave_account_password_strength_meter.html.ts
@@ -0,0 +1,26 @@
+/* Copyright (c) 2026 The Brave Authors. All rights reserved.
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+import { html } from '//resources/lit/v3_0/lit.rollup.js'
+
+import { BraveAccountPasswordStrengthMeter } from './brave_account_password_strength_meter.js'
+
+export function getHtml(this: BraveAccountPasswordStrengthMeter) {
+ return html`
+
+
+ ${this.category === 'Weak'
+ ? '$i18n{BRAVE_ACCOUNT_PASSWORD_STRENGTH_METER_WEAK}'
+ : this.category === 'Medium'
+ ? '$i18n{BRAVE_ACCOUNT_PASSWORD_STRENGTH_METER_MEDIUM}'
+ : '$i18n{BRAVE_ACCOUNT_PASSWORD_STRENGTH_METER_STRONG}'}
+
+ `
+}
diff --git a/components/brave_account/resources/brave_account_password_strength_meter.ts b/components/brave_account/resources/brave_account_password_strength_meter.ts
new file mode 100644
index 00000000000..5aa6a5e8996
--- /dev/null
+++ b/components/brave_account/resources/brave_account_password_strength_meter.ts
@@ -0,0 +1,89 @@
+/* Copyright (c) 2026 The Brave Authors. All rights reserved.
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+import {
+ CrLitElement,
+ PropertyValues,
+} from '//resources/lit/v3_0/lit.rollup.js'
+
+import {
+ BraveAccountBrowserProxy,
+ BraveAccountBrowserProxyImpl,
+} from './brave_account_browser_proxy.js'
+import { getCss } from './brave_account_password_strength_meter.css.js'
+import { getHtml } from './brave_account_password_strength_meter.html.js'
+
+export type PasswordStrengthChangedEventDetail = { isStrongEnough: boolean }
+
+export class BraveAccountPasswordStrengthMeter extends CrLitElement {
+ static get is() {
+ return 'brave-account-password-strength-meter'
+ }
+
+ static override get styles() {
+ return getCss()
+ }
+
+ override render() {
+ return getHtml.bind(this)()
+ }
+
+ static override get properties() {
+ return {
+ category: { type: String, reflect: true },
+ strength: { type: Number, state: true },
+ password: { type: String },
+ }
+ }
+
+ override async updated(changedProperties: PropertyValues) {
+ super.updated(changedProperties)
+
+ if ((changedProperties as Map).has('password')) {
+ const password = this.password
+ try {
+ const { strength } =
+ await this.browserProxy.password_strength_meter.getPasswordStrength(
+ password,
+ )
+
+ // Ignore stale response if password changed while we were waiting.
+ if (this.password !== password) {
+ return
+ }
+
+ this.strength = strength
+ } catch (error) {
+ console.error('Failed to calculate password strength:', error)
+ this.strength = 0
+ }
+
+ this.category =
+ this.strength < 60 ? 'Weak' : this.strength < 100 ? 'Medium' : 'Strong'
+
+ this.fire('password-strength-changed', {
+ isStrongEnough: this.strength === 100,
+ })
+ }
+ }
+
+ private browserProxy: BraveAccountBrowserProxy =
+ BraveAccountBrowserProxyImpl.getInstance()
+
+ protected accessor category: 'Weak' | 'Medium' | 'Strong' = 'Weak'
+ protected accessor strength = 0
+ private accessor password = ''
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'brave-account-password-strength-meter': BraveAccountPasswordStrengthMeter
+ }
+}
+
+customElements.define(
+ BraveAccountPasswordStrengthMeter.is,
+ BraveAccountPasswordStrengthMeter,
+)
diff --git a/resources/resource_ids.spec b/resources/resource_ids.spec
index 5da7d376f12..5454d590425 100644
--- a/resources/resource_ids.spec
+++ b/resources/resource_ids.spec
@@ -215,7 +215,7 @@
"includes": [53980],
},
"<(SHARED_INTERMEDIATE_DIR)/brave/components/brave_account/resources/resources.grd": {
- "META": {"sizes": {"includes": [35]}},
+ "META": {"sizes": {"includes": [40]}},
"includes": [54000],
},
"brave/ios/web/test/test_resources.grd": {