Skip to content

feat(PasswordInput)!: build the frame and the toggle, like Number Input - #695

Merged
mrholek merged 4 commits into
v6-devfrom
feat/password-input-builds-its-frame-v6
Aug 4, 2026
Merged

feat(PasswordInput)!: build the frame and the toggle, like Number Input#695
mrholek merged 4 commits into
v6-devfrom
feat/password-input-builds-its-frame-v6

Conversation

@mrholek

@mrholek mrholek commented Aug 4, 2026

Copy link
Copy Markdown
Member

Number Input landed with the component owning its frame and its buttons, so the markup is a plain form control. Password Input already owned the icon; this gives it the rest.

- <div class="form-control-group">
-   <input type="password" class="form-control">
-   <button type="button" class="form-control-action" data-coreui-toggle="password" aria-label="Toggle password visibility"></button>
- </div>
+ <input type="password" class="form-control" data-coreui-toggle="password-input">

What changes

  • data-coreui-toggle moves from the button to the input, and its value becomes the component's name — password-input, matching number-input. There is no button left in the markup to carry it.
  • Classes other than .form-control move onto the frame. A class on the control describes the field, and once the input is wrapped the field is the frame — mb-3 left behind would put the margin inside the border. They move back on dispose().
  • An input already inside a .form-control-group is left alone, so a password field can share a frame with other adornments; only a frame the component created is removed on dispose().
  • ariaToggleLabel is a new option: the button is no longer the author's to label.

One helper, not two copies

The wrapping is ensureControlGroup / releaseControlGroup in util/form-control-group.ts, used by both components. Number Input's inline version is gone — its 20 tests pass against the shared one unchanged, which is the check that mattered for the extraction.

The helper carries the rule Number Input arrived at, with the reasoning in one place rather than restated per component.

Verification

  • 26 password unit tests. The data-api block is rewritten against the new contract — frame and toggle built on init, clicking toggles both type and aria-pressed, disabled control gets a disabled button, several fields stay independent, classes round-trip through dispose(), an authored group survives.
  • 20 Number Input tests unchanged, on the shared helper.
  • 33 visual baselines; the password ones and the input-group one regenerated. The input-group case keeps a hand-authored frame — with the password markup no longer containing one, that case would otherwise have stopped covering what it was written for.
  • Full docs pass: every example is a bare control, the Usage section describes the new contract, and the customization section gains the note about the authored group and the moved classes. Migration guide carries the markup diff.

Bundlewatch budgets nudged for the shared helper; CSS unchanged.

The component already owned the icon; it owns the button and the frame that
lays it out now, so the markup is a plain form control:

  <input type="password" class="form-control" data-coreui-toggle="password-input">

data-coreui-toggle moves from the button to the input - there is no button
in the markup to put it on - and its value becomes the component's name, so
it reads the same as Number Input's.

The wrapping is one helper shared by both components rather than a copy in
each: ensureControlGroup / releaseControlGroup in util/form-control-group.
It carries the rule Number Input arrived at, that every class except
.form-control moves to the frame, because a class on the control describes
the field and the field is the frame once it is wrapped.

The accessible name of the toggle is an option now (ariaToggleLabel), since
the button is no longer the author's to label.
@coveralls

coveralls commented Aug 4, 2026

Copy link
Copy Markdown

Coverage Report for CI Build 30940890853

Coverage increased (+0.02%) to 92.965%

Details

  • Coverage increased (+0.02%) from the base build.
  • Patch coverage: 49 of 49 lines across 3 files are fully covered (100%).
  • 2 coverage regressions across 2 files.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

2 previously-covered lines in 2 files lost coverage.

File Lines Losing Coverage Coverage
js/src/navigation.ts 1 64.63%
js/src/password-input.ts 1 91.07%

Coverage Stats

Coverage Status
Relevant Lines: 8668
Covered Lines: 8272
Line Coverage: 95.43%
Relevant Branches: 4821
Covered Branches: 4268
Branch Coverage: 88.53%
Branches in Coverage %: Yes
Coverage Strength: 362.41 hits per line

💛 - Coveralls

mrholek added 3 commits August 4, 2026 20:44
The Visual job has been passing on every pull request by generating
baselines rather than checking against them: with no *-chromium-linux.png
in the tree, the matcher creates the set and the run ends green. Visual
regressions were only ever caught on a maintainer's machine.

These are the 33 the job generated on this branch, so they carry the
markup this pull request settles. The next run compares.
The comment said the spinner rules were verified in all three engines.
Two were measured; Playwright's WebKit would not launch here, which the
pull request body said and the comment did not. It now states what was
measured and what each rule leaves behind when used alone.
@mrholek
mrholek merged commit e8795e2 into v6-dev Aug 4, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants