-
Notifications
You must be signed in to change notification settings - Fork 707
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
[Portal] Explore giving more control for layering #760
Comments
This is great! Thanks! One other reason why this is tricky is because most (if not all) of these components have |
On this, I was just about to ask why we need the provider thing also. Because, like all parts we expose, we can control when/how they render still and if they're wrapping it around Pseudo-code: const DialogPortal = (props) => {
return <Presence present={forceMount || context.open}><Portal {...props} /></Presence>
}
const DialogContent = (props) => {
const forceMount = context.isInsidePortal || props.forceMount;
return <Presence present={forceMount || context.open}><DialogContentImpl {...props} /></Presence>
} |
And then we'd conditionally render the portal for them inside |
Why do we need to conditionally render the |
Ha ok, you're talking about them always having to render the |
Yep, annoying thing there though is that if they want all their dialogs to portal they would have to wrap into their own parts: export const DialogOverlay = (props) => {
return <DialogPrimitive.Portal><DialogPrimitive.Overlay {...props} /></DialogPrimitive.Portal>;
}
export const DialogContent = () => {
return <DialogPrimitive.Portal><DialogPrimitive.Content {...props} /></DialogPrimitive.Portal>;
} Which isn't ideal, BUT, it does give them the control to do this #345 Also, most people will want to close over things like |
It's definitely a DX concern. If we were to make all components that can be portalled have to render the portal part, then yes DX wise there's more work to do for each of those. |
Yep agreed, that's why we've always avoided this historically and why I suggested the prop but I'm starting to wonder if it's that big of a deal. Most of our parts are required for the majority of use-cases but we always make folks render them too, it's an open API. The docs would just provide examples they could copy/paste as always. <Dialog.Root>
<Dialog.Trigger>Open</Dialog.Trigger>
<Dialog.Portal><Dialog.Overlay /></Dialog.Portal>
<Dialog.Portal><Dialog.Content /></Dialog.Portal>
</Dialog.Root>
<Dialog.Root>
<Dialog.Trigger>Open</Dialog.Trigger>
<Dialog.Portal>
<Dialog.Overlay>
<Dialog.Content />
</Dialog.Overlay>
</Dialog.Portal>
</Dialog.Root> I dunno... I was against it before but starting to re-consider (especially because of #345 which is how I've always composed my dialogs 😅 ). This approach aligns so much better with my opinions on composability. I've always been against boolean props that render parts for this reason because obviously, if we just give the parts to consumers they can choose when to enable them and where to wrap them and can add whatever DOM props they need. I'd still like to see what else we can come up with though. I feel like the |
Another benefit of exposing https://discord.com/channels/752614004387610674/803656530259738674/872829639742078976 |
Coming here from this: https://discord.com/channels/752614004387610674/875105353568768010/875333950392926238 I would absolutely be in favor of the Portal! My use case is to be able to center <Dialog.Content /> without the transform method. |
Not sure if this is revelant, but having a hard time using Dropdown inside a Dialog. The radix portal seems to add style={{pointer-events:none}} to the body tag, which then the Dropdown inside Dialog directly inherits from body. There's sometimes some funky stuff like this happening or portals opening on a layer that is unexpected. |
@MildTomato Is there a particular bug you're experiencing? I've just tried the composition you describe and things appear to be working okay for me: https://codesandbox.io/s/serverless-dust-pvolx
I agree this would be useful and is one of the main requests we get 🤞 |
Someone wanted to achieve a grid layout with Exposing the |
Sorry - i think i was using older version of both Dialog and Dropdown (or maybe just 1 of them). |
Ran into a similar layout issue. I wanted to render a sidebar dialog, but it can't have the highest z-index and it needs to fill the height of a container. Dialogs couldn't work because the default portal can't be turned off, and Popover is too difficult for this scenario since it depends on an anchor and I can't turn off positioning. |
While @vladmoroz was building the new primitives docs site he wanted to inject the dialog into a different container instead of the |
I would also love to see this. My use case is that I have a form inside a dialog; if form submission fails, I show an error message in a toast widget [which is more consistent with the rest of our UI than putting the error message inside the dialog content]. Right now, the dialog overlay is covering up the toast, which obviously needs to be on top. |
Having more control here would be really helpful. My use-case is that I'm using react-toastify to show toasts; on mobile I'm using modals as full-page takeovers and sometimes want to show a toast over it. I can use I think exposing Portal in the Dialog primitive makes sense and will allow more control over how the Dialog renders. It's definitely a little more overhead but not much more than having to compose all the other parts anyway and will give developers much more control over how things behave. |
We've published a release candidate for this in Dialog and AlertDialog to try. The API has breaking changes with this change so we would love feedback on the approach before we roll it out across our other components. The new anatomy is as follows: <Dialog.Root>
<Dialog.Trigger />
<Dialog.Portal>
<Dialog.Overlay />
<Dialog.Content />
</Dialog.Portal>
</Dialog.Root> Note:
|
@jjenzz This is great! Looking forward to updating my component library. |
@jjenzz Thanks! I was able to update to the latest RC and can confirm that it works with the use-case I described earlier and resolved issues I was running into. 👍 |
@jjenzz YES! |
@radix-ui stopped putting z-index on portal component so tablekit adjusted to use its own z-indices reference: radix-ui/primitives#760 (comment)
@radix-ui stopped putting z-index on portal component so tablekit adjusted to use its own z-indices reference: radix-ui/primitives#760 (comment)
For my tooltips I need to control where the tooltip portal renders. So more control would be really nice here |
Can we do this for Dropdown as well? I have a dropdown that has drag-n-drop list inside it, and during dragging i have a floating item that needs to be layered above the Dropdown. |
@sikanhe The plan is to do it for all of our portalled components I believe. |
We currently apply the maximum
z-index
on portals and have had a few requests to allow more control here. This ticket is to explore ways of allowing that for a few reasons:data-radix-portal
attribute atmdata-radix-portal
attribute is an inconsistent escape hatch that we removed from other compsAn initial discussion on this topic provided a couple ideas:
layer
/zIndex
prop for portalled parts, e.g.<DialogContent layer={3}>
APortal
provider part exposed per component that provides its props to the internal portal, e.g.<DialogPortal style={{ zIndex: 3 }}><DialogContent /></DialogPortal>
. The provider suggestion is because we need control internally of how/where/when the portal is rendered.Portal
part for people to wrap when they want portals, e.g.Dialog.Portal
. Examples.Slot
internally on thePortal
. This would reduce elements rendered as an additional win but it wouldn't work with:Popper
based parts because popper wraps its own additionaldiv
for positioningRemoveScroll
part for it to work, andRemoveScroll
isn't slot-aware.The text was updated successfully, but these errors were encountered: