From f7c3956667500fbcf06ad9b6ab94403bc7d040f2 Mon Sep 17 00:00:00 2001 From: Bartosz-Do Date: Fri, 25 Sep 2026 12:13:40 +0200 Subject: [PATCH] Fix strength meter binding the field after it instead of before it (#3192) Co-authored-by: codecalm --- .changeset/strength-precedes-input.md | 5 ++++ core/js/src/strength.ts | 9 ++++--- core/js/tests/unit/strength.spec.ts | 39 +++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 .changeset/strength-precedes-input.md diff --git a/.changeset/strength-precedes-input.md b/.changeset/strength-precedes-input.md new file mode 100644 index 000000000..59ae8a0f4 --- /dev/null +++ b/.changeset/strength-precedes-input.md @@ -0,0 +1,5 @@ +--- +"@tabler/core": patch +--- + +Fixed the strength meter rating a confirm-password field after it instead of the password field before it. diff --git a/core/js/src/strength.ts b/core/js/src/strength.ts index 3c35baa71..09527364b 100644 --- a/core/js/src/strength.ts +++ b/core/js/src/strength.ts @@ -170,11 +170,14 @@ class Strength extends BaseComponent { return SelectorEngine.findOne(input) as HTMLInputElement | null } - // Without an explicit selector only the meter's own parent is searched, so - // a form with several password fields cannot bind the wrong one. + // Without an explicit selector only the meter's own parent is searched. + // The nearest field before the meter wins, so a confirm-password field + // placed after it is never mistaken for the one being rated; a meter + // placed above its field falls back to the first field after it. const parent = this._element.parentElement const fields = parent ? (SelectorEngine.find(SELECTOR_PASSWORD, parent) as HTMLInputElement[]) : [] - return fields[fields.length - 1] ?? null + const precedingFields = fields.filter((field) => Boolean(field.compareDocumentPosition(this._element) & Node.DOCUMENT_POSITION_FOLLOWING)) + return precedingFields[precedingFields.length - 1] ?? fields[0] ?? null } _getText(): HTMLElement | null { diff --git a/core/js/tests/unit/strength.spec.ts b/core/js/tests/unit/strength.spec.ts index 8380d68f9..c5014f56c 100644 --- a/core/js/tests/unit/strength.spec.ts +++ b/core/js/tests/unit/strength.spec.ts @@ -69,6 +69,45 @@ describe('Strength', () => { expect(instance._input).toBe(fixtureEl.querySelector('#remote')) }) + + it('should bind the password field before it, not a confirm field after it', () => { + fixtureEl.innerHTML = ` +
+ +
+ +
` + + const instance = new Strength(meter()) + + expect(instance._input).toBe(fixtureEl.querySelector('#pw')) + }) + + it('should bind the last of several preceding fields, ignoring one after it', () => { + fixtureEl.innerHTML = ` +
+ + +
+ +
` + + const instance = new Strength(meter()) + + expect(instance._input).toBe(fixtureEl.querySelector('#new')) + }) + + it('should bind the field after it when none precedes it', () => { + fixtureEl.innerHTML = ` +
+
+ +
` + + const instance = new Strength(meter()) + + expect(instance._input).toBe(fixtureEl.querySelector('#confirm')) + }) }) describe('levels', () => {