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

Big dropdowns are unusable when used inside an overflow:scroll container, due to being constrained inside it #24251

Closed
ronjouch opened this issue Oct 4, 2017 · 16 comments

Comments

@ronjouch
Copy link

ronjouch commented Oct 4, 2017

Problem

When using a Bootstrap (4.0.0beta) Dropdown in an element that is a child of an overflow:scroll element, the dropdown is "stuck" inside the container, making it unusable if the dropdown contents are too big horizontally/vertically:

overflow-scroll_bootstrap-dropdown-fs8

Contrarily, a vanilla HTML <select> will merrily bleed out of the overflow:scroll element as necessary:
overflow-scroll_regular-select-fs8

See demo at JSFiddle/ronj/t6z6Lnfb.

Use case

A few words on the use case justifying this combination, as shown in the JSFiddle which mimics a webapp I'm working on:

  • In the left sidebar live a set of filters. It may contain several filters that will consume undetermined vertical space, thus lives in an overflow-y:scroll div. Each filter has a dropdown which lets users modify filter options.
  • In the right pane lives the content, filtered by the filters in the left sidebar.

→ As a user,

  1. I do need that overflow-y:scroll sidebar scrolling behavior (because the list of filters is of undetermined and potentially large height, depending on the number of filters)
  2. But filter dropdowns (which can be large, both in width due to length of options and height due to count of options) should be able "escape out of" / not be constrained by the sidebar.

And as shown in the demo/screenshots, vanilla HTML <select> don't suffer from this problem, but it's not always practical/possible to revert back to using them, e.g. due to using features specific to Bootstrap Dropdown, or for consistent styling.

Details

Bootstrap version: 4.0.0-beta

OS/Browser: Ubuntu 16.04.3 / {Chrome 63, Firefox 58}

This issue is a follow-up to SO / Letting a bootstrap b-dropdown escape out of an overflow:scroll container, but noticing regular <select> are not affected, it starts to look like a bug, thus this issue. Sorry for the noise if I'm missing something obvious / if there's a workaround / if this is a known problem tracked in an existing issue.

Thanks 🙂.

@danijelGombac
Copy link

danijelGombac commented Oct 4, 2017

Try this:

$(document).on('show.bs.dropdown', '.scrolled-heighted-box', function(e) {
        var dropdown = $(e.target).find('.dropdown-menu');

            dropdown.appendTo('body');
        $(this).on('hidden.bs.dropdown', function () {
            dropdown.appendTo(e.target);
        })
    });

I use this for table responsive.

@ronjouch
Copy link
Author

ronjouch commented Oct 4, 2017

@danijelGombac works in the jsFiddle, thanks 👍👍👍! I'm using Bootstrap from Vue.js with bootstrap-vue though, so I guess I have a bit of fiddling to do, but it looks doable.

Still looks like desirable-by default behavior to me, so leaving the issue open.

@mdo
Copy link
Member

mdo commented Oct 5, 2017

Curious if this is doable with Popper @Johann-S? Previously we have been constrained by the manual placement of dropdowns in the DOM.

@Johann-S
Copy link
Member

Johann-S commented Oct 5, 2017

Yep we can add a container option the same used for Tooltips/Popovers and the Dropdown will be append inside this other container and will be positioned correctly

@ronjouch
Copy link
Author

ronjouch commented Oct 5, 2017

Yep we can add a container option the same used for Tooltips/Popovers and the Dropdown will be append inside this other container and will be positioned correctly

@Johann-S @mdo thanks for the fast feedback 🙂! A proper fix in vanilla Bootstrap would be awesome, because even though the re-parenting trick works for vanilla Bootstrap, turns out my "I guess it's doable in bootstrap-vue with a bit of fiddling" comment at #24251 (comment) was wrong: re-parenting is a no-no for downstream reactive bindings like bootstrap-vue. Quoting @tmorehouse at bootstrap-vue/bootstrap-vue#1163 (comment) ,

Re-parenting live reactive components (such as the components inside a dropdown) is not the greatest thing to do with Vue, as it can start complaining that the parent element has changed, cause a re-render (back to the original spot, and cause elements to be "stuck" where ever they weer re-parented if for some reason the original container or component gets removed from the document (i.e. v-if, a route change, etc).

The biggest issue is the latter (i.e. dropdown menus that get stuck open on a page when their parent component goes away). While you can try and use beforeDestroy/destroyed hooks to move the content back to where it was supposed to be, it doesn't always work (as the place where it is supposed to be in the DOM no longer exists.. Which can also lead to application memory leaks if event listeners have references to those DOM elements (so they may get removed from DOM, but are still in memory because someone else has a reference to it).

@tmorehouse anything to comment on that container option proposed in twbs/bootstrap PR#24257? I see our b-popover / b-tooltip components do expose it and guess a similar property should be portable to b-dropdown too, right?

@tmorehouse
Copy link
Contributor

tmorehouse commented Oct 5, 2017

@ronjouch regarding b-popover/b-tooltips, dynamically creatd new DOM elements are appended to the DOM (body by default, or the optional container) when the tip/popover opens. b-dropdown is different in that reactive content (i.e. the dropdown items which most likely have event listeners) are created by components outside of the dropdown component scope (even through they are children)

We could try a re-parenting option, but it would require a new "dumb" wrapper element around the .dropdown-menu that Vue.JS doesn't monitor. The only issue is that anything that dynamically changes in the dropdown component (i.e button text, enabling/disabling split button, variants, changing props, etc) that would cause Vue to re-render the component would most likely create new elements, leaving the old re-parented sub-items duplicatedand "stranded" in the DOM.

@FezVrasta
Copy link
Contributor

FezVrasta commented Nov 2, 2017

An usually unknown behavior of DOM and CSS is that an overflow: scroll element doesn't implicitly means that nothing can actually overflow from its boundaries.

image
https://codepen.io/FezVrasta/pen/GOoRxM

The only situation when an overflow: scroll element becomes completely "un-overflowable" is when it, or one of its children, also have a position different from static

image
https://codepen.io/FezVrasta/pen/KyVKRb

This behavior can be leveraged to make a popper overflow its scrolling parent.

image
https://codepen.io/FezVrasta/pen/pdgoMX

In our specific case, the .dropdown wrapper has position: relative, and it forces the dropdown to always get hidden by any overflow: scroll parent

As side note, Popper.js is not completely optimized for this specific use case, some work is needed to update the algorithm used to detect the bounding parent elements.

@tmorehouse
Copy link
Contributor

tmorehouse commented Nov 5, 2017

@FezVrasta this appears to be a bit buggy in Firefox, and doesn't handle when the dropdown is wider than the container. It is still partially off screen.

When setting the column to col-2:
image

@FezVrasta
Copy link
Contributor

FezVrasta commented Nov 5, 2017

@tmorehouse the problem with col-2 is because Popper.js is not yet optimized for this use case.

About Firefox, it looks like it's only the outline property that acts weirdly, other styling is fine.

If this approach is something that Bootstrap wants to adopt I can work on Popper.js to make it work better to fit this need.

@tmorehouse
Copy link
Contributor

tmorehouse commented Dec 8, 2017

@FezVrasta, @Johann-S @mdo @ronjouch For Bootstrap-Vue we have just added an option (via PR bootstrap-vue/bootstrap-vue#1440) to change the modifiers.preventOverflow.boundariesElement (i.e. from the default of scrollParent to viewport or window), and if anything other than scrollParent is set, we add the CSS position: static to the outer wrapper around the dropdown button(s) (i.e. the div.dropdown).

Popper.js reference: https://popper.js.org/popper-documentation.html#modifiers..preventOverflow

This appears to work well from our tests so far, while still preserving the default behavior when scrollParent is set as the boundariesElement and does not require re-parenting the .dropdown-menu.

Before (with boundariesElement at default, and no position: static, which is the current behavior):

image

Now (with the boundary set to viewport or window, and position: static):

image

Which renders the following if boundary is set to something other than 'scrollParent':

<div class="dropdown" style="position: static">
  <button class="dropdown-toggle">Dropdown</button>
  <div class="dropdown-menu">
    <!-- dropdown items here -->
  </div>
</div>

@Johann-S
Copy link
Member

Johann-S commented Dec 8, 2017

seems nice @tmorehouse I'll give it a look 👍

@tmorehouse
Copy link
Contributor

tmorehouse commented Dec 8, 2017

@Johann-S We have also done something similar for popover/tooltip (without the use of position: static, but with the boundariesElement option), which allows the popover/tooltip placement to work when the trigger element is inside an element with overflow: scroll). position: static wasn't needed in the tooltip/popover case as the tooltip/popover is typically appended to the body. PR bootstrap-vue/bootstrap-vue#1439

Basically we have added a boundary config property in the tooltip class (defaults to 'scrollParent'), which the user can override. The boundary value is passed directly to the Popper config modifiers.preventOverflow.boundariesElement

@tmorehouse
Copy link
Contributor

tmorehouse commented Dec 8, 2017

@Johann-S I could create a couple of PRs that would address this issue for dropdowns and for tooltips/popover (would just be a few lines of code in the tooltip class, and a few lines in the dropdown plugin).

Update: PR's created #24976 and #24978

gnucifer added a commit to ub-digit/fjarrkontrollen that referenced this issue Mar 1, 2019
Overflow scroll elements doesn't play well with overflowing children
with position anything but static:
twbs/bootstrap#24251

Fix by padding with spacer div since user switcher has a known
maximum height.
gnucifer added a commit to ub-digit/fjarrkontrollen that referenced this issue Mar 1, 2019
Overflow scroll elements doesn't play well with overflowing children
with position anything but static:
twbs/bootstrap#24251

Fix by padding with spacer div since user switcher has a known
maximum height.
kebeclibre added a commit to odoo-dev/odoo that referenced this issue Sep 30, 2019
Open a search view modal ("search more" on a m2o)
Select a filter that will make records fall to zero
The modal will shrink
Trigger the opening of a dropdown (Filters), and make sure
that there are many many menu items there (many filters)

Before this commit, the dropdown was bigger than the modal
which had a scroll bar,
however, the dropdown itself was not scrollable properly
So, clicking in it to select a menu item will fail when scrolled
all the way down, because elements did not actually followed the scroll

After this commit, the dropdown follows the scroll, and it is possible
to use it even way down

We use a behavior of bootstrap 4 itself:
FIX: twbs/bootstrap#24976
ISSUE: twbs/bootstrap#24251

OPW 2076337
robodoo pushed a commit to odoo/odoo that referenced this issue Oct 7, 2019
Open a search view modal ("search more" on a m2o)
Select a filter that will make records fall to zero
The modal will shrink
Trigger the opening of a dropdown (Filters), and make sure
that there are many many menu items there (many filters)

Before this commit, the dropdown was bigger than the modal
which had a scroll bar,
however, the dropdown itself was not scrollable properly
So, clicking in it to select a menu item will fail when scrolled
all the way down, because elements did not actually followed the scroll

After this commit, the dropdown follows the scroll, and it is possible
to use it even way down

We use a behavior of bootstrap 4 itself:
FIX: twbs/bootstrap#24976
ISSUE: twbs/bootstrap#24251

OPW 2076337

closes #37594

Signed-off-by: Lucas Perais (lpe) <lpe@odoo.com>
fw-bot pushed a commit to odoo-dev/odoo that referenced this issue Oct 7, 2019
Open a search view modal ("search more" on a m2o)
Select a filter that will make records fall to zero
The modal will shrink
Trigger the opening of a dropdown (Filters), and make sure
that there are many many menu items there (many filters)

Before this commit, the dropdown was bigger than the modal
which had a scroll bar,
however, the dropdown itself was not scrollable properly
So, clicking in it to select a menu item will fail when scrolled
all the way down, because elements did not actually followed the scroll

After this commit, the dropdown follows the scroll, and it is possible
to use it even way down

We use a behavior of bootstrap 4 itself:
FIX: twbs/bootstrap#24976
ISSUE: twbs/bootstrap#24251

OPW 2076337

X-original-commit: c3273b7
fw-bot pushed a commit to odoo-dev/odoo that referenced this issue Oct 7, 2019
Open a search view modal ("search more" on a m2o)
Select a filter that will make records fall to zero
The modal will shrink
Trigger the opening of a dropdown (Filters), and make sure
that there are many many menu items there (many filters)

Before this commit, the dropdown was bigger than the modal
which had a scroll bar,
however, the dropdown itself was not scrollable properly
So, clicking in it to select a menu item will fail when scrolled
all the way down, because elements did not actually followed the scroll

After this commit, the dropdown follows the scroll, and it is possible
to use it even way down

We use a behavior of bootstrap 4 itself:
FIX: twbs/bootstrap#24976
ISSUE: twbs/bootstrap#24251

OPW 2076337

X-original-commit: c3273b7
fw-bot pushed a commit to odoo-dev/odoo that referenced this issue Oct 7, 2019
Open a search view modal ("search more" on a m2o)
Select a filter that will make records fall to zero
The modal will shrink
Trigger the opening of a dropdown (Filters), and make sure
that there are many many menu items there (many filters)

Before this commit, the dropdown was bigger than the modal
which had a scroll bar,
however, the dropdown itself was not scrollable properly
So, clicking in it to select a menu item will fail when scrolled
all the way down, because elements did not actually followed the scroll

After this commit, the dropdown follows the scroll, and it is possible
to use it even way down

We use a behavior of bootstrap 4 itself:
FIX: twbs/bootstrap#24976
ISSUE: twbs/bootstrap#24251

OPW 2076337

X-original-commit: c3273b7
robodoo pushed a commit to odoo/odoo that referenced this issue Oct 7, 2019
Open a search view modal ("search more" on a m2o)
Select a filter that will make records fall to zero
The modal will shrink
Trigger the opening of a dropdown (Filters), and make sure
that there are many many menu items there (many filters)

Before this commit, the dropdown was bigger than the modal
which had a scroll bar,
however, the dropdown itself was not scrollable properly
So, clicking in it to select a menu item will fail when scrolled
all the way down, because elements did not actually followed the scroll

After this commit, the dropdown follows the scroll, and it is possible
to use it even way down

We use a behavior of bootstrap 4 itself:
FIX: twbs/bootstrap#24976
ISSUE: twbs/bootstrap#24251

OPW 2076337

closes #38069

X-original-commit: c3273b7
Signed-off-by: Lucas Perais (lpe) <lpe@odoo.com>
robodoo pushed a commit to odoo/odoo that referenced this issue Oct 7, 2019
Open a search view modal ("search more" on a m2o)
Select a filter that will make records fall to zero
The modal will shrink
Trigger the opening of a dropdown (Filters), and make sure
that there are many many menu items there (many filters)

Before this commit, the dropdown was bigger than the modal
which had a scroll bar,
however, the dropdown itself was not scrollable properly
So, clicking in it to select a menu item will fail when scrolled
all the way down, because elements did not actually followed the scroll

After this commit, the dropdown follows the scroll, and it is possible
to use it even way down

We use a behavior of bootstrap 4 itself:
FIX: twbs/bootstrap#24976
ISSUE: twbs/bootstrap#24251

OPW 2076337

closes #38057

X-original-commit: c3273b7
Signed-off-by: Lucas Perais (lpe) <lpe@odoo.com>
robodoo pushed a commit to odoo/odoo that referenced this issue Oct 7, 2019
Open a search view modal ("search more" on a m2o)
Select a filter that will make records fall to zero
The modal will shrink
Trigger the opening of a dropdown (Filters), and make sure
that there are many many menu items there (many filters)

Before this commit, the dropdown was bigger than the modal
which had a scroll bar,
however, the dropdown itself was not scrollable properly
So, clicking in it to select a menu item will fail when scrolled
all the way down, because elements did not actually followed the scroll

After this commit, the dropdown follows the scroll, and it is possible
to use it even way down

We use a behavior of bootstrap 4 itself:
FIX: twbs/bootstrap#24976
ISSUE: twbs/bootstrap#24251

OPW 2076337

closes #38080

X-original-commit: c3273b7
Signed-off-by: Lucas Perais (lpe) <lpe@odoo.com>
robodoo pushed a commit to odoo/odoo that referenced this issue Oct 7, 2019
Open a search view modal ("search more" on a m2o)
Select a filter that will make records fall to zero
The modal will shrink
Trigger the opening of a dropdown (Filters), and make sure
that there are many many menu items there (many filters)

Before this commit, the dropdown was bigger than the modal
which had a scroll bar,
however, the dropdown itself was not scrollable properly
So, clicking in it to select a menu item will fail when scrolled
all the way down, because elements did not actually followed the scroll

After this commit, the dropdown follows the scroll, and it is possible
to use it even way down

We use a behavior of bootstrap 4 itself:
FIX: twbs/bootstrap#24976
ISSUE: twbs/bootstrap#24251

OPW 2076337

closes #38069

X-original-commit: c3273b7
Signed-off-by: Lucas Perais (lpe) <lpe@odoo.com>
@SoftCircuits
Copy link

All of this and apparently no official response? Still an issue in 2022.

@mdo
Copy link
Member

mdo commented Mar 3, 2022

@SoftCircuits Commenting on a four year old issue without looking through the referenced issues and PRs isn't helpful. We did ship an official response by adding boundary options in the plugins. See #24976.

If you're still having an issue, I highly suggest opening a new issue with a live demo to see if there's something else we can do.

@TondeMoon
Copy link

@SoftCircuits if you add data-boundary="viewport" to bootstrap menu element and position-static to parent container with .dropdown class, the problem goes away. Positioning is still not ideal but it works.

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

No branches or pull requests

8 participants