Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dropdowns: Modified Dropdown's _parent to use a new method called 'cl… #41037

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

classicmike
Copy link

@classicmike classicmike commented Nov 19, 2024

Dropdowns: Modified Dropdown's _parent to use a new method called 'closest', to allow dropdown menus to not necessarily be the sibling of the trigger button element. So instead of trying to use dropdown wrapper as the direct parent, it can be an ancestor.

Description

This is a non-breaking improvement change to the Dropdown and Selector Engine JS files. More in the Motivation or context. But the long story short is that inside the dropdown's constructor, instead of setting this._parent to the direct parent element, this change will use a new method for the selector engine called closest which will find the closest ancestor that contains the dropdown menu element. This will then allow a not-so restrictive DOM structure. All existing behaviour as per Bootstrap documentation remains the same.

Motivation & Context

Currently, I'm trying to create web components that use Bootstrap's dropdowns as the main mechanism for our dropdowns in our design system. Currently based on the Dropdown's constructor, this._parent is set to only use the this._element's direct parent. So as per documentation, it allows usages like this:

<div class="dropdown">
  <a class="btn btn-secondary dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
    Dropdown link
  </a>

  <ul class="dropdown-menu">
    <li><a class="dropdown-item" href="#">Action</a></li>
    <li><a class="dropdown-item" href="#">Another action</a></li>
    <li><a class="dropdown-item" href="#">Something else here</a></li>
  </ul>
</div>

Which is fine for most use cases. However, in our use case, since it is a design system, we also create web components for things such as buttons like this:

<design-system-dropdown>
    <design-system-button>Trigger Dropdown</design-system-button>
    <design-system-dropdown-menu>
        <design-system-dropdown-item>
            <a href="https://google.com" target="_blank">Go to Google</a>
        </design-system-dropdown-item>
    </design-system-dropdown-menu>
</design-system-dropdown>

On render, the HTML would look something typical to this:

<design-system-dropdown class="dropdown">
    <design-system-button>
        <button class="btn btn-primary dropdown-trigger" data-bs-toggle="dropdown">Trigger Dropdown</button>
    </design-system-button>
    <design-system-dropdown-menu class class="dropdown-menu">
        <design-system-dropdown-item>
            <a href="https://google.com" class="dropdown-item" target="_blank">Go to Google</a>
        </design-system-dropdown-item>
    </design-system-dropdown-menu>
</design-system-dropdown>

As you can see in the above, the button with the data-bs-toggle which is the element in the dropdown constructor is not a sibling of the .dropdown-menu element, so when the dropdown open is called, the code is stuck because of the restrictive HTML structure.

The proposed changes will address the issue whilst maintaining the original intent of the HTML structure of these elements, and works for the current HTML structure. I have tested this with all of the combinations within the Bootstrap documentation including dropdowns inside navbars, split dropdown and standard default use cases.

In terms of documentation, I don't feel a change is required on that front since all of the use cases in the documentation have not changed.

Type of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Refactoring (non-breaking change)
  • Breaking change (fix or feature that would change existing functionality)

Checklist

  • I have read the contributing guidelines
  • My code follows the code style of the project (using npm run lint)
  • My change introduces changes to the documentation
  • I have updated the documentation accordingly
  • I have added tests to cover my changes
  • All new and existing tests passed

…osest', to allow dropdown menus to not necessarily be the sibling of the trigger button element. So instead of trying to use dropdown wrapper as the direct parent, it can be an ancestor.
@classicmike classicmike requested a review from a team as a code owner November 19, 2024 01:06
@@ -95,7 +95,8 @@ class Dropdown extends BaseComponent {
super(element, config)

this._popper = null
this._parent = this._element.parentNode // dropdown wrapper
const wrapperSelector = `:has(${SELECTOR_MENU})`
Copy link
Member

Choose a reason for hiding this comment

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

Just for information, :has cannot be used right now in Bootstrap v5 because of our browser support (see .browserslistrc. It'll be upgraded in v6.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants