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
Unexpected behavior when composing Popover and Tooltip on the same element #3754
Comments
@diegohaz thanks for adding the tag. Just to add some more context on this - we're seeing some odd, probably related, behavior to this in our app - the Popover just doesn't open if the composition is such that the Example app code: <Popover>
<Popover.Content>...</Popover.Content>
<Popover.Trigger>
<Tooltip content="more info">
<Button>i</Button>
</Tooltip>
</Popover.Trigger>
</Popover> Under the hood this roughly translates to this implementation: It makes a lot more sense to keep the Tooltip wrapping the button, rather than above the entire Popover, the content of which might be long. If you think that this is a separate bug/issue (maybe because of the |
It indeed appears to be the same problem. Thanks for the reproductions. FWIW, you don't need - <Ariakit.PopoverDisclosure ref={ref} render={<Slot />}>
- {children}
- </Ariakit.PopoverDisclosure>
+ <Ariakit.PopoverDisclosure ref={ref} render={children} /> This also forces you to improve type safety because you'll need to type |
Thanks for the tip, good idea. I hacked the Stackblitz repro pretty quickly, but I'll make sure our actual codebase's types are better.
About the bug itself, do you happen to have an (even rough) ETA on fixing this? We want to migrate our Popover and Tooltip components to be based on Ariakit, and this is the only blocker for us. Or maybe you could give me some pointers so I can try to fix it myself and send a PR. |
I can't provide an ETA right now. This kind of issue probably needs more thinking than actual coding. You don't need to wait, though. If you're still stuck, we should find a workaround that works for you. If your implementation mirrors the last StackBlitz link you posted, then there's no need to use const tooltip = Ariakit.useTooltipStore();
<>
<Ariakit.Tooltip store={tooltip}>{content}</Ariakit.Tooltip>
<Ariakit.TooltipAnchor {...props} store={tooltip} render={children} />
</> |
Thanks, our const PopoverScopeContext = React.createContext<{ store: AriakitPopoverStore }>(
null
);
function usePopoverScope() {
const value = React.useContext(PopoverScopeContext);
assert(value != null);
return value;
}
function PopoverRoot({ open, setOpen, ...rest }: PopoverProps) {
const store = PopoverPrimitive.usePopoverStore({
open: props.open,
setOpen: props.setOpen,
});
return (
<PopoverScopeContext.Provider store={store} {...rest}>
{rest.children}
</PopoverScopeContext.Provider>
);
}
const PopoverTrigger = React.forwardRef(
({ asChild, ...props }: PopoverTriggerProps, ref: RefOf<"button">) => {
const { store } = usePopoverScope();
return (
<Ariakit.PopoverDisclosure
ref={ref}
store={store}
render={asChild ? <Slot /> : undefined}
{...props}
/>
);
}
);
// and similarly to `PopoverTrigger` wrapping `<Ariakit.PopoverDisclosure>` and passing in the store explicitly
// the same for `PopoverContent` -> `<Ariakit.Popover>` @diegohaz Does this make sense as a workaround until this bug is fixed? |
Yes, that's a perfectly valid use of the lower-level API. |
I meant the fact that I self-pass the Popover's store rather than the Tooltip's, as you suggested. Why would changing one work while the other wouldn't? (I originally tried doing the Tooltip's, as suggested, but that didn't fix the popover-not-opening issue). |
Ah, I missed the part where you said the popover doesn't open. The popover isn't opening on the StackBlitz link you shared because you're not spreading the remaining props onto As you can see in the snippet I shared: <Ariakit.TooltipAnchor {...props} store={tooltip} render={children} />
// ^^^^^^^^ |
Right, that's a miss on my end in the reproduction. In the app code we do have it spread props of course. <Popover>
<Popover.Content>
Nisi esse consectetur deserunt. Veniam eu irure nulla sint cillum
proident nisi sunt proident dolor exercitation laboris qui.
</Popover.Content>
<Tooltip content="more info"> // A
<Popover.Trigger> // B
<Button>i</Button>
</Popover.Trigger>
</Tooltip>
</Popover> Switching up lines A & B fixes it, but tell that to consumers... So I think that this is now the original bug I opened the issue on, correct? Where a Popover & Tooltips mix, such that the Tooltip acts as a Popover, from a user's perspective, and the actual popover content is nowhere to be found. |
Exactly, that's why I suggested #3754 (comment) |
Current behavior
Using a Tooltip and a Popover on the same element doesn't always works as expected - both show up when hovering the anchor element.
This only seems to happen based on the order of the providers:
broken:
working:
I guess this is because of the way these two interact internally, so they share the same store even though they should have entirely separate ones, but I'm not sure.
Steps to reproduce the bug
https://stackblitz.com/edit/vitejs-vite-iuggxs?file=src%2FApp.tsx,src%2Fstyle.css
Expected behavior
The order of providers shouldn't matter in this case.
Workaround
Change around the Providers' order such that:
Or #3754 (comment)
Possible solutions
Give each usage of a provider type a name (e.g.
"TooltipHovercardStore"
) such that even if two components use the same underlying primitives (e.g. Hovercard), they won't share stores since they consume it using separate names.The text was updated successfully, but these errors were encountered: