Skip to content

Conversation

absumo
Copy link
Contributor

@absumo absumo commented Sep 1, 2025

Summary by Sourcery

Add a configurable password visibility toggle to Symfony forms by implementing a PasswordType extension, Stimulus controller, accompanying assets, translations, and documentation, replacing the previous UX dependency

New Features:

  • Introduce a custom password visibility toggle feature for PasswordType and RepeatedPasswordStrengthType fields via a new form extension and Stimulus controller

Enhancements:

  • Allow configuring toggle behavior through labels, icons, CSS classes, and optional form theme integration
  • Remove the symfony/ux-toggle-password dependency in favor of the new implementation
  • Include translation keys and SCSS imports for toggle-password styling

Build:

  • Remove symfony/ux-toggle-password from composer dependencies

Documentation:

  • Document the toggle-password usage and customization options in the Stimulus frontend guide

Copy link

sourcery-ai bot commented Sep 1, 2025

Reviewer's Guide

This pull request implements a password visibility toggle by introducing a Symfony form type extension, registering it as a service, wiring in a Stimulus controller, updating Twig and SCSS assets, enhancing translations, updating documentation, and removing the previous UX package dependency.

Sequence diagram for password visibility toggle interaction

sequenceDiagram
    actor User
    participant PasswordInput as Password Input Field
    participant ToggleButton as Toggle Button
    participant StimulusController as Stimulus Controller
    User->>ToggleButton: Clicks toggle button
    ToggleButton->>StimulusController: Event: click
    StimulusController->>PasswordInput: Change type (password/text)
    StimulusController->>ToggleButton: Update label and icon
Loading

Class diagram for TogglePasswordTypeExtension

classDiagram
    class TogglePasswordTypeExtension {
        - TranslatorInterface translator
        + __construct(translator: TranslatorInterface|null)
        + getExtendedTypes(): iterable
        + configureOptions(resolver: OptionsResolver): void
        + buildView(view: FormView, form: FormInterface, options: array): void
        - translateLabel(label: string|TranslatableMessage|null, translationDomain: string|null): string|null
    }
    TogglePasswordTypeExtension --|> AbstractTypeExtension
Loading

Class diagram for Stimulus toggle_password_controller.js

classDiagram
    class TogglePasswordController {
        + visibleLabelValue: String
        + visibleIconValue: String
        + hiddenLabelValue: String
        + hiddenIconValue: String
        + buttonClassesValue: Array
        - isDisplayed: Boolean
        - visibleIcon: String
        - hiddenIcon: String
        + connect(): void
        + createButton(): HTMLButtonElement
        + toggle(event): void
        + dispatchEvent(name: String, payload: Object): void
    }
    TogglePasswordController --|> Controller
Loading

File-Level Changes

Change Details Files
Introduce TogglePasswordTypeExtension to augment PasswordType with visibility toggle
  • Define a new form type extension with toggle options, defaults, and allowed types
  • Inject translator to handle label translations
  • Build view vars for controller data attributes and optional form theming
src/Form/Extension/TogglePasswordTypeExtension.php
Register the TogglePasswordTypeExtension as a form type extension
  • Import and configure the extension service in DI container
  • Tag the service for PasswordType type_extension and inject translator
config/services.php
Add Stimulus controller for password toggle behavior
  • Implement connect, button creation, toggle logic, and custom events
  • Provide default and overrideable icons and labels
assets-public/controllers/toggle_password_controller.js
Add Twig form theme block for toggle widget
  • Insert toggle_password_widget block wrapping the password input
  • Apply dynamic container classes for styling
templates/Form/fields.html.twig
Add SCSS styling and import for toggle-password UI
  • Import toggle-password component in main SCSS entry
  • Create component styles for container, button, and icon
assets/scss/_imports.scss
assets/scss/components/_toggle-password.scss
Update translation files with Show/Hide labels
  • Add 'Show' and 'Hide' entries in English messages
  • Add corresponding 'Toon' and 'Verberg' in Dutch
translations/messages.en.yml
translations/messages.nl.yml
Update documentation for Password Visibility Toggle
  • Append usage section and customization options to stimulus.md
docs/frontend/stimulus.md
Remove symfony/ux-toggle-password dependency
  • Delete the UX package entry from composer.json
composer.json

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there - I've reviewed your changes - here's some feedback:

Blocking issues:

  • User controlled data in methods like innerHTML, outerHTML or document.write is an anti-pattern that can lead to XSS vulnerabilities (link)
  • User controlled data in a button.innerHTML is an anti-pattern that can lead to XSS vulnerabilities (link)
  • User controlled data in methods like innerHTML, outerHTML or document.write is an anti-pattern that can lead to XSS vulnerabilities (link)
  • User controlled data in a toggleButtonElement.innerHTML is an anti-pattern that can lead to XSS vulnerabilities (link)

General comments:

  • The service definition for TogglePasswordTypeExtension reuses the ‘framework.collection_type_extension’ ID and will override your collection extension; give it a unique service ID (e.g. ‘framework.toggle_password_type_extension’) and tag it appropriately.
  • Using bare translation keys like “Show” and “Hide” risks collisions in large apps; consider namespacing them (e.g. ‘toggle_password.show’, ‘toggle_password.hide’) in your message files.
  • In the docs snippet, the array entry 'use_toggle_form_theme' => false is missing a trailing comma—adding it will prevent a PHP parse error.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The service definition for TogglePasswordTypeExtension reuses the ‘framework.collection_type_extension’ ID and will override your collection extension; give it a unique service ID (e.g. ‘framework.toggle_password_type_extension’) and tag it appropriately.
- Using bare translation keys like “Show” and “Hide” risks collisions in large apps; consider namespacing them (e.g. ‘toggle_password.show’, ‘toggle_password.hide’) in your message files.
- In the docs snippet, the array entry 'use_toggle_form_theme' => false is missing a trailing comma—adding it will prevent a PHP parse error.

## Individual Comments

### Comment 1
<location> `assets-public/controllers/toggle_password_controller.js:44` </location>
<code_context>
+    const button = document.createElement('button')
+    button.type = 'button'
+    button.classList.add(...this.buttonClassesValue)
+    button.setAttribute('tabindex', '-1')
+    button.addEventListener('click', this.toggle.bind(this))
+    button.innerHTML = `${this.visibleIcon} ${this.visibleLabelValue}`
</code_context>

<issue_to_address>
Setting tabindex to -1 prevents keyboard navigation to the toggle button.

Users who rely on keyboard navigation will be unable to access the toggle button. To maintain accessibility, use tabindex="0" or omit it.
</issue_to_address>

## Security Issues

### Issue 1
<location> `assets-public/controllers/toggle_password_controller.js:46` </location>

<issue_to_address>
**security (javascript.browser.security.insecure-document-method):** User controlled data in methods like `innerHTML`, `outerHTML` or `document.write` is an anti-pattern that can lead to XSS vulnerabilities

*Source: opengrep*
</issue_to_address>

### Issue 2
<location> `assets-public/controllers/toggle_password_controller.js:46` </location>

<issue_to_address>
**security (javascript.browser.security.insecure-innerhtml):** User controlled data in a `button.innerHTML` is an anti-pattern that can lead to XSS vulnerabilities

*Source: opengrep*
</issue_to_address>

### Issue 3
<location> `assets-public/controllers/toggle_password_controller.js:56` </location>

<issue_to_address>
**security (javascript.browser.security.insecure-document-method):** User controlled data in methods like `innerHTML`, `outerHTML` or `document.write` is an anti-pattern that can lead to XSS vulnerabilities

*Source: opengrep*
</issue_to_address>

### Issue 4
<location> `assets-public/controllers/toggle_password_controller.js:56` </location>

<issue_to_address>
**security (javascript.browser.security.insecure-innerhtml):** User controlled data in a `toggleButtonElement.innerHTML` is an anti-pattern that can lead to XSS vulnerabilities

*Source: opengrep*
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

const button = document.createElement('button')
button.type = 'button'
button.classList.add(...this.buttonClassesValue)
button.setAttribute('tabindex', '-1')
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: Setting tabindex to -1 prevents keyboard navigation to the toggle button.

Users who rely on keyboard navigation will be unable to access the toggle button. To maintain accessibility, use tabindex="0" or omit it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Te bekijken lijkt me.

button.classList.add(...this.buttonClassesValue)
button.setAttribute('tabindex', '-1')
button.addEventListener('click', this.toggle.bind(this))
button.innerHTML = `${this.visibleIcon} ${this.visibleLabelValue}`
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security (javascript.browser.security.insecure-document-method): User controlled data in methods like innerHTML, outerHTML or document.write is an anti-pattern that can lead to XSS vulnerabilities

Source: opengrep

button.classList.add(...this.buttonClassesValue)
button.setAttribute('tabindex', '-1')
button.addEventListener('click', this.toggle.bind(this))
button.innerHTML = `${this.visibleIcon} ${this.visibleLabelValue}`
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security (javascript.browser.security.insecure-innerhtml): User controlled data in a button.innerHTML is an anti-pattern that can lead to XSS vulnerabilities

Source: opengrep

Comment on lines +56 to +58
toggleButtonElement.innerHTML = this.isDisplayed
? `${this.hiddenIcon} ${this.hiddenLabelValue}`
: `${this.visibleIcon} ${this.visibleLabelValue}`
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security (javascript.browser.security.insecure-document-method): User controlled data in methods like innerHTML, outerHTML or document.write is an anti-pattern that can lead to XSS vulnerabilities

Source: opengrep

Comment on lines +56 to +58
toggleButtonElement.innerHTML = this.isDisplayed
? `${this.hiddenIcon} ${this.hiddenLabelValue}`
: `${this.visibleIcon} ${this.visibleLabelValue}`
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security (javascript.browser.security.insecure-innerhtml): User controlled data in a toggleButtonElement.innerHTML is an anti-pattern that can lead to XSS vulnerabilities

Source: opengrep

export default class extends Controller {
static values = {
visibleLabel: { type: String, default: 'Show' },
visibleIcon: { type: String, default: 'Default' },
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Voor mij moeten die icons niet configureerbaar zijn. Is enkel maar bloated code. Tenzij anderen daar een andere mening over hebben natuurlijk.

const button = document.createElement('button')
button.type = 'button'
button.classList.add(...this.buttonClassesValue)
button.setAttribute('tabindex', '-1')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Te bekijken lijkt me.

'use_toggle_form_theme' => false

// Customizing labels and icons
'hidden_label' => 'Masquer',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eventueel ook echt met translation service in voorbeeld steken. Zodat mensen het kunnen kopiëren.


## Password Visibility Toggle

This works automatically when you use the `PasswordType` or `RepeatedPasswordStrengthType` in your form type.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Zet een voorbeeld zodat mensen het eenvoudig kunnen kopiëren .


'Text copied!': 'Test copied!'
'Postcode and municipality': Postcode and municipality
Show: Show
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Misschien beter Show password en Hide password gebruiken als labels. Die zijn minder generiek.

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