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

Z-Index doesn't seem to be configurable #5329

Open
haveamission opened this issue Sep 2, 2022 · 9 comments · May be fixed by #5830
Open

Z-Index doesn't seem to be configurable #5329

haveamission opened this issue Sep 2, 2022 · 9 comments · May be fixed by #5830
Labels
issue/bug-unconfirmed Issues that describe a bug that hasn't been confirmed by a maintainer yet

Comments

@haveamission
Copy link

haveamission commented Sep 2, 2022

Thanks for using react-select!

If you are going to ask a question or want to propose a change or a new feature, then please don't file an issue for this.
Questions and feature requests have their own place in our discussions section.

Are you reporting a bug or runtime error?

A bug. No matter what I try, looking back at the examples nor at the previous issue queue, I cannot affect z-index whatsoever.

Screen Shot 2022-09-02 at 3 29 48 PM

Code is fairly standard:

const modelSelector = [
  { value: 'Ferrari 812 GTS', label: 'Ferrari 812 GTS' },
  { value: 'Ferrari 296 GTB', label: 'Ferrari 296 GTB' },
  { value: 'Ferrari 296 GTS', label: 'Ferrari 296 GTS' },
]

const ModelSelector = () => (
  <Select options={modelSelector} placeholder="Model" />
)

I've tried all sorts of style stuff, like this:

const customStyles = {
  option: (provided: any, state: any) => ({
    ...provided,
    zIndex: 999,
  }),
  control: () => ({
    zIndex: 999,
  }),
  singleValue: (provided: any, state: any) => {
    const opacity = state.isDisabled ? 0.5 : 1
    const transition = 'opacity 300ms'

    return { ...provided, opacity, transition, zIndex: 99999 }
  },
}

No luck.

This is in a React Native Web application, if that makes any difference.

How do I get z-index to work? If I put the z-index of everythingI want underneath the dropdown to -1 it works, but that's obviously not a great solution

@haveamission haveamission added the issue/bug-unconfirmed Issues that describe a bug that hasn't been confirmed by a maintainer yet label Sep 2, 2022
@eckmLJE
Copy link

eckmLJE commented Sep 26, 2022

EDIT: Sorry, I meant to mention in my comment that for the menuPortal approach to work, you need to be working with portals, and pass e.g. document.body to the menuPortalTarget in the Select. If you are having z-index problems, portaling the menu is your best bet, because there are many situations down the DOM tree that can establish new stacking contexts that render your z-index value useless. By portaling to the document body, you are in the base stacking context, and you can establish a z-index hierarchy that makes sense. Here's an example of using portals to the body and a z-index hierarchy to ensure the menu always appears on top, even in complicated situations:

react-select.with.portals.and.z-index.mp4

I believe you want to target menuPortal in the select's style object:

<Select
  ...
  styles={{
    menuPortal: provided => ({
      ...provided,
      zIndex: 100 // arbitrary z-index value, you should reference your z-index scale/strategy for this value
    })
  }}
/>

The menu portal is the positioned container that holds the menu. Depending on your stacking context / z-index setup, you may need to use menuPosition="fixed" as well on the select.

@GuySartorelli
Copy link

I opened a PR to address this late last year: #5830

@eckmLJE
Copy link

eckmLJE commented Feb 23, 2024

Sorry, I meant to mention in my comment that for the menuPortal approach to work, you need to pass e.g. document.body to the menuPortalTarget in the Select. If you are having z-index problems, portaling the menu is your best bet, because there are many situations down the DOM tree that can establish new stacking contexts that render your z-index value useless. By portaling to the document body, you are in the base stacking context, and you can establish a z-index hierarchy that makes sense. Here's an example of using portals to the body and a z-index hierarchy to ensure the menu always appears on top, even in complicated situations:

react-select.with.portals.and.z-index.mp4

@GuySartorelli
Copy link

GuySartorelli commented Feb 25, 2024

It seems to me that if the expected setup is that document.body must be passed to menuPortalTarget for the z-index to work in even fairly simple cases (and this is a problem even in some very simple scenarios), then either
a) that should be explicitly called out in both the "Installation and usage" section of the README and in all documentation that users are likely to first hit when trying to use this component, or
b) that should be already set by default

That said, it really seems like overkill to require this, when a large z-index can be set by default, which is what my PR does. It solves this problem in a lot of cases, which makes the menuPortalTarget solution a workaround for complex scenarios rather than a requirement for basic ones.

@eckmLJE
Copy link

eckmLJE commented Feb 25, 2024

You can certainly accomplish handling z-index without portals, but portals are the most straightforward way without actually understanding z-index and stacking context. Setting a very high (even the highest possible) z-index on an element is often not enough to cause it to appear above other elements.

For example, in this codepen, you have two parent elements, one has z-index of 1 (.container-a), the other doesn't have a z-index value (.container-b). Then a child of .container-a has a z-index value of 1, and a child of .container-b has a z-index of 1000.

Guess which child appears on top? The div with a z-index of 1, or of 1000? It's the div with a z-index of 1, because its parent established a new stacking context that is higher than that of its sibling, and setting a high z-index value of the sibling's child at that point will do nothing to make it appear on top.

There are other gotchas with z-index as well that can cause new stacking contexts to be established that are unpredictable.

So, just setting some arbitrary high z-index value is not helpful. You can certainly build your site's layout to avoid creating gotchas like that, but trying to build a generalized solution to this problem by just giving the select menu a high z-index won't do it. The default of 1 already places it above its sibling content given z-index is not set on other elements.

Portals are a reliable way to solve this problem, and it's a feature that react-select provides. If you're careful with how you set up your layout in the first place, it's likely you can avoid needing to use z-index at all. But if you start running into complicated situations, you'll be happy to have the tool available. When you start messing with z-index such that your menu is not appearing on top of content around it, then either you need to dig into understanding your particular z-index situation, or you should reach for portals.

Portals are also useful when your select is inside a container with overflow: hidden and you need your select menu to appear outside the container.

Josh Comeau has a great (as always) piece on z-index if you'd like to learn more about it: https://www.joshwcomeau.com/css/stacking-contexts/

@eckmLJE
Copy link

eckmLJE commented Feb 25, 2024

I agree that the react-select docs don't give an in-depth explanation of what portaling is or why you'd need it, or how do deal with z-index. From their docs

React-select exposes a menuPortalTarget prop, that lets you portal the select menu to a dom node of your choosing. Additionally we expose the menuPortal styles for layering purposes.

They're definitely letting "for layering purposes" do a lot of work there. They're assuming that if you have a z-index/layering issue, you will investigate other resources that will help you understand common solutions to the stacking problem, and then understand how to use the tools react-select provides for you. It's a complicated issue and it's not necessarily their job to teach you how z-index works.

@GuySartorelli
Copy link

I'm not saying this project is or should be responsible for reaching anyone how z-index works.
What I am saying is that the default scenario should work for as many generalised cases as possible (and setting a high z-index does solve this problem in many cases - not all, sure, but many).

Failing that, the documentation should highlight portaling very early on if it's the intended solution to this not-uncommon problem.

@eckmLJE
Copy link

eckmLJE commented Feb 26, 2024

The bottom line is that the default menu z-index of 1 already does work for almost every situation where you're not setting your own z-index on other elements. z-index: 1; (the least you can set it above the starting css value of 0) puts the menu above all browser defaults. If you are setting other things at 1 or higher, then you're taking on the responsibility of managing z-index. Then, without using portals, you can set the menu component's z-index value with the styling approaches detailed in the docs for many situations where you're not juggling more complex layering. Then, when you do have those situations, you can use portals. Arguing to set some arbitrary "high" z-index value (your PR suggested 20,000, when the maximum allowed value is 2,147,483,647 -- so is it actually high? what if the library consumer's z-index hierarchy starts at 100,000?) as the default goes against the fundamentals of how z-index works and is managed.

@GuySartorelli
Copy link

GuySartorelli commented Feb 26, 2024

If you are setting other things at 1 or higher, then you're taking on the responsibility of managing z-index

I'm suggesting that there's almost no (or more likely: literally no) scenario where the react select menu should not be above other elements. So this seems like an odd decision.

Seems like anyone wanting other elements to be rendered over the menu is a much less likely scenario - so that should be when people have to add workarounds, not "you have set any z-index on any element, therefore you have to also do something about this menu element".

I'm also suggesting that even if that is the decision the maintainers want to go with, it needs to be better documented.

your PR suggested 20,000, when the maximum allowed value is 2,147,483,647 -- so is it actually high? what if the library consumer's z-index hierarchy starts at 100,000?

I'm happy to bump the value to 2,147,483,647 in my PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
issue/bug-unconfirmed Issues that describe a bug that hasn't been confirmed by a maintainer yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants