React-datepicker: the z-index for the datepicker container is too damn high!

Created on 30 Mar 2017  路  16Comments  路  Source: Hacker0x01/react-datepicker

It appears that the z-index for datepicker__tether-element changed from 2 to 2147483647 with this commit: https://github.com/Hacker0x01/react-datepicker/commit/227d92a6ca3f875d6c86ec49a58732a0d7faab4c#diff-9da5657b359639ae904fe748a1fb2b4cR309

This isn't a difficult thing to override, but it's annoying that the number chosen is the upper bound for z-index in most browsers. Since this is a plugin I'd expect a more reasonable default z-index value (perhaps 3 would have been a better option for example).

To illustrate the problem I added a fixed position header to your demo page and gave it the same z-index as the calendar wrapper.

screen shot 2017-03-29 at 3 22 34 pm

I'd be happy to submit a PR with a different number, but felt opening an issue would be best in case there's a good reason it was set so high. Is there something non-obvious that this fixes, or is there perhaps something obvious I'm missing?

Thanks in advance for your time and help! :D

wontfix

All 16 comments

Not a maintainer, but did you actually encounter an issue with this?

I can't imagine a use case where someone wanted the datepicker to be hidden under something else. It's like a modal - when it's open, it should be visible, and components should have defaults that handle the the typical use. z-index of 3 is far too low. You can always override it if need be.

I did encounter an issue. Unlike with a modal, users will (and should) still be able to scroll the page if the date picker is open. It's not exactly breaking anything but it does not look good to have the date picker hovering over the fixed header for the app this is being used in (which is what I was trying to demonstrate with the image in the original post). We override it but conceptually this is closer to a dropdown than a modal, and giving it the highest possible z-index doesn't make it very portable. 3 makes sense for a z-index to me since it should really just pop over its immediate surroundings, but I do agree it could be bigger. I opened an issue instead of a PR since the commit attached to the change doesn't have any context as to why it was changed but I assumed it fixed some issue for one or more people.

come to think of it, the problem here is more than aesthetic, since depending on the placement of your datepicker and buttons on your header, it could block clicking on them. You shouldn't need to click out of a date picker or drop down before you click on a menu item.

Fair point, altho I don't think you'd have this issue if you put your header into a separate stacking context which seems more typical.

If you look at my image I believe I am putting the example header into a separate stacking context.

The header is in #app [data-reactroot] .hero header (with the header having a fixed position)
The datepicker is in #app [data-reactroot] .hero .hero__content .hero__example .react-datepicker__*

Am I missing something here?

does .hero__content have a z-index and position: relative or something to give it a stacking context?

heh not sure it's from the demo page of this plugin :D

So I've never used the term stacking context, but it seems it's simply used for describing the hierarchy of an HTML page. From my experience if you have a child nested deep into the page it will definitely render above all of its parents if you give it a z-index that's high enough. Once I got better at understanding these hierarchies I was able to range my z-indices between [-1, 2] (with a -1 being a very special case) as long as I structured my HTML properly. Where I get into trouble is when plugins choose some arbitrarily high number, which completely destroys that nice relative z-index pattern (which I believe is what you're referring to a couple of comments above about stacking context). It's the main reason choosing a z-index that's the highest possible z-index for a browser is not a very nice default for a plugin as it forces the plugin to always be the most important thing on the page no matter what (which is what I attempted to demonstrate with my screen grab in the OP).

Are we on the same page now @jcrben? Or is there something I'm still missing? I don't even work at the company that's using this plugin anymore, and the person who pointed the issue out to me got around it by over-riding the z-index in the app's style sheet. However, I do love learning new things so if I'm wrong about something here, I'd love to learn why :D

er also, I checked the demo page, there's no relative position or any other z-index on the container elements of that page

From my experience if you have a child nested deep into the page it will definitely render above all of its parents if you give it a z-index that's high enough

No, the z-index of a child in a stacking context will only apply within the stacking context. So if you create a stacking context for the header with z-index 3 and a stacking context for the main content with z-index 2, everything inside the main body will be under the header. The MDN article explains it better than I can.

hm so if I give .hero__content a relative position and z-index of 1, and I nest this header directly inside of the data-reactroot a fixed position, z-index of 9999, then the .hero__content should never cover the header?

That's what I did and it didn't work. This MDN article discussion on stacking context appears to be describing why a child with z-index of 6 can still render under a parent with a z-index of 2 and that it depends on how deep that child is nested inside of the parent. My understanding is that it's basically a simple sum based on how many nodes the child would need to move to be at the same level as (or above) its parent. If you choose a z-index which is larger than the number of nests, then it doesn't matter if a few of the intermediate elements have a sane z-index, that child will always have the top level stacking context of the page (not sure if I'm using the term stacking context correctly here :p).

See this new image of me doing it again based on our discussion here, notice I even render the header outside of the .hero element and the datepicker still blocks it. To test your and my assumptions it'd be super helpful if you opened up the inspector and added some html/css to demonstrate what you think is happening. Obviously this isn't a demand or anything, but if you're able to make the datepicker render under a fixed header on that demo page without changing the z-index of the datepicker container and screen grab/share it here it'd probably be really obvious what I'm missing. If you're unable to do this, then it'll probably be really obvious what you're missing.

I appreciate the introduction of a new term! If you don't feel like demonstrating your point that's totally cool, but if what you're saying is actually true then I'd love to see a screen grab of it happening so I can reproduce it on my own and learn something about z-index that I didn't know before :)
screen shot 2017-05-22 at 7 35 42 pm

As MDN says, "the z-index values of its child stacking contexts only have meaning in this parent" - it has nothing to do with how deep the child is. There might be some caveats where a nested high z-index could trump a sibling of the parent's stacking context but I'm not aware of them. This is one of the reasons people use https://github.com/tajo/react-portal.

In this case, you need to look for the react-datepicker__tether-element, which is attached as a child of the body! And since 2147483647 is the highest possible z-index, it looks like you'd have to override that to reduce it in your own css. Which also gets tricky because you'd still have to create a stacking context that beats it...

Dialing the z-index down is an idea, but perhaps allowing people to customize where react-datepicker__tether-element is attached would be more flexible.

aaand boom goes the dynamite.

Thank you so much for staying with me this long man! I missed the tethering element on the body somehow. I'm guessing that'd be a tough one to move since it's likely being used to determine when the menu is colliding with the top of the body, and for positioning etc. Regardless, even 999 would be a better z-index here so I think I'll keep my issue open, but I'm very grateful that you took the time to explain this concept of stacking contexts to me. I knew that these orders were relative but always assumed there was some global order in general (which er, yes there's that too but it's obviously different than what I thought). It's pretty sweet to know I can reign these things in easier than I thought before, although I tend to keep my z-index values pretty small which is probably why I've never hit this upper limit issue before (er unless I'm dealing with a plugin, but then I just override if I can). Thanks again man, hopefully my lack of understanding wasn't too frustrating :p

but perhaps allowing people to customize where react-datepicker__tether-element is attached would be more flexible.

I believe the renderCalendarTo prop is what you are looking for.

renderCalendarTo is it. Might be worth mentioning in the website example that it shows only a subselection of options. Also wish https://github.com/Hacker0x01/react-datepicker/blob/master/docs/datepicker.md had more descriptions. Maybe I'll open a PR at some point but I'm moving on to other tickets right now...

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

hoodsy picture hoodsy  路  3Comments

ro-savage picture ro-savage  路  3Comments

ali-master picture ali-master  路  3Comments

jbccollins picture jbccollins  路  3Comments

pinturic picture pinturic  路  3Comments