openedx / paragon

💎 An accessible, theme-ready design system built for learning applications and Open edX.
https://paragon-openedx.netlify.app
Apache License 2.0
121 stars 67 forks source link

z-index revamp (z-index hooks) #2990

Open brian-smith-tcril opened 10 months ago

brian-smith-tcril commented 10 months ago

from @bradenmacdonald on slack

Hey folks, does Paragon have a philosophy for handling z-index conflicts? For example, we are trying to use a Form.Autosuggest inside a modal, and the autosuggest dropdown is appearing behind parts of the modal (screenshot). I couldn't see any docs about this, and could only find these pre-defined z-index classes. If that's all that Paragon has right now, it's too simplistic. Because obviously a modal should normally be higher than a dropdown, but a dropdown in a modal should be higher than a modal. I would also argue that if you had a proper layer system, you could put popover and tooltip lower than modal as well.

One approach I know of for solving this is using utility classes (Tailwind style). Currently, the Form.Autosuggest has some code like .pgn__form-autosuggest__dropdown { ... z-index: $zindex-dropdown; ... } . Adding CSS rules to give such components a higher z-index conditionally (when they're in a modal) is problematic, because either the Autosuggest component has to be aware of all the possible layers like modals and account for them (.modal-layer & { z-index: $zindex-modal + $zindex-dropdown }) or the Modal component has to be aware of all the possible components and account for them (& .dropdown { z-index: $zindex-modal + $zindex-dropdown). => But if you use a small set of predefined classes like .zindex-dropdown so that the autosuggest has that extra utility class, then it's a bit easier to plan for the interactions like .zindex-modal .zindex-dropdown .zindex-tooltip { z-index: $zindex-modal + $zindex-dropdown + $zindex-tooltip } (a tooltip over a dropdown in a modal), and your components don't have to otherwise be aware of each other.

But as you can see from the example of "a tooltip in a dropdown in a modal", managing those rules can still get complex. So I have found that a simple zindex hook provides the cleanest solution for this problem, by using the React tree to determine the z-index of each component by using the z-index of its parent (from context) and adding some fixed amount based on the type of component. (example of use in a Modal)

bradenmacdonald commented 5 months ago

Apparently, using CSS isolation: isolate may be an even simpler way to solve this issue :)

Ref: https://x.com/adamwathan/status/1798704643222212683