ui
ui copied to clipboard
`Popover` don't open when combined with `Tooltip`
I tried to make TooltipButton
and PopoverButton
components to nicely nest them when needed. However, Popover won't open when doing it (and vice versa). Here is my demo: https://codesandbox.io/p/sandbox/tooltip-popover-forked-dh3zq3?file=%2Fsrc%2FApp.tsx%3A58%2C40
While tooltip works fine, popover won't open. If I nest popover inside tooltip, then popover works but tooltip doesnt. What should I change? I would really like to have separate components for Tooltip
and Popover
instead of having to nest them in single component like describe here: https://www.radix-ui.com/primitives/docs/guides/composition#composing-multiple-primitives
I could be wrong but shouldn't your code look like this?
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
export function PopoverDemo() {
return (
<TooltipProvider>
<Popover>
<PopoverTrigger asChild>
<Tooltip>
<TooltipTrigger asChild>
<Button variant="outline">Open popover</Button>
</TooltipTrigger>
<TooltipContent>
<p>Add to library</p>
</TooltipContent>
</Tooltip>
</PopoverTrigger>
<PopoverContent className="w-80">
<div className="grid gap-4">
<div className="space-y-2">
<h4 className="font-medium leading-none">Dimensions</h4>
<p className="text-sm text-muted-foreground">
Set the dimensions for the layer.
</p>
</div>
<div className="grid gap-2">
<div className="grid grid-cols-3 items-center gap-4">
<Label htmlFor="width">Width</Label>
<Input
id="width"
defaultValue="100%"
className="col-span-2 h-8"
/>
</div>
<div className="grid grid-cols-3 items-center gap-4">
<Label htmlFor="maxWidth">Max. width</Label>
<Input
id="maxWidth"
defaultValue="300px"
className="col-span-2 h-8"
/>
</div>
<div className="grid grid-cols-3 items-center gap-4">
<Label htmlFor="height">Height</Label>
<Input
id="height"
defaultValue="25px"
className="col-span-2 h-8"
/>
</div>
<div className="grid grid-cols-3 items-center gap-4">
<Label htmlFor="maxHeight">Max. height</Label>
<Input
id="maxHeight"
defaultValue="none"
className="col-span-2 h-8"
/>
</div>
</div>
</div>
</PopoverContent>
</Popover>
</TooltipProvider>
);
}
I'm sorry if I didn't understand what you meant.
@Caio-Tera I'd like to create to separate components, one for TooltipButton and another one for PopoverButton and eventually use them both when needed instead of crating this long chain as you did. Why my code doesnt work, i.e. this part?:
const tooltipButtonWithPopover = (
<TooltipButton trigger={popoverButtonWithoutTooltip}>
Tooltip Content
</TooltipButton>
);
Does this make any sense to you?
I couldn't test whether it renders.
But I imagine this is the beginning of a solution?
import React from 'react';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
export function PopoverComponent({
trigger,
body,
}: {
trigger: React.ReactNode;
body: React.ReactNode;
}) {
return (
<Popover>
<PopoverTrigger asChild>{trigger}</PopoverTrigger>
<PopoverContent className="w-80">{body}</PopoverContent>
</Popover>
);
}
export function TooltipComponent({
trigger,
body,
}: {
trigger: React.ReactNode;
body: React.ReactNode;
}) {
return (
<Tooltip>
<TooltipTrigger asChild>{trigger}</TooltipTrigger>
<TooltipContent>{body}</TooltipContent>
</Tooltip>
);
}
export function PopoverBody() {
return (
<div className="grid gap-4">
<div className="space-y-2">
<h4 className="font-medium leading-none">Dimensions</h4>
<p className="text-sm text-muted-foreground">
Set the dimensions for the layer.
</p>
</div>
<div className="grid gap-2">
<div className="grid grid-cols-3 items-center gap-4">
<Label htmlFor="width">Width</Label>
<Input id="width" defaultValue="100%" className="col-span-2 h-8" />
</div>
<div className="grid grid-cols-3 items-center gap-4">
<Label htmlFor="maxWidth">Max. width</Label>
<Input
id="maxWidth"
defaultValue="300px"
className="col-span-2 h-8"
/>
</div>
<div className="grid grid-cols-3 items-center gap-4">
<Label htmlFor="height">Height</Label>
<Input id="height" defaultValue="25px" className="col-span-2 h-8" />
</div>
<div className="grid grid-cols-3 items-center gap-4">
<Label htmlFor="maxHeight">Max. height</Label>
<Input
id="maxHeight"
defaultValue="none"
className="col-span-2 h-8"
/>
</div>
</div>
</div>
);
}
export function Rootlayout() {
return (
<TooltipProvider>
<PopoverComponent
trigger={
<TooltipComponent
trigger={<Button variant="outline">Open popover</Button>}
body={<p>Add to library</p>}
/>
}
body={<PopoverBody />}
/>
</TooltipProvider>
);
}
@Caio-Tera how does it differ from my current implementaion? I also splitted it into to separate components which does not work. I would appreciate if someone could actually fix my code and indicate what was wrong with him.
This worked for me - Tooltip and Popover working together:
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
type ToolbarTooltipProps = {
content: string; // Or could be another React.ReactNode.
children: React.ReactNode;
};
export const ToolbarTooltip = ({ content, children }: ToolbarTooltipProps) => {
return (
<Tooltip>
<TooltipTrigger asChild>{children}</TooltipTrigger>
<TooltipContent side="bottom" sideOffset={20}>
{content}
</TooltipContent>
</Tooltip>
);
};
"use client";
import { Button } from "@/components/ui/button";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import { ToolbarTooltip } from "./ToolbarTooltip";
export const SomeComponent = () => {
return (
<Popover>
<ToolbarTooltip content="Background">
<PopoverTrigger asChild>
<Button variant={"ghost"} className="h-full">
Trigger
</Button>
</PopoverTrigger>
</ToolbarTooltip>
<PopoverContent className="z-50">....</PopoverContent>
</Popover>
);
};
This issue has been automatically closed because it received no activity for a while. If you think it was closed by accident, please leave a comment. Thank you.
in my case this is worked for me
<TooltipProvider>
<Popover>
<Tooltip delayDuration={100}>
<PopoverTrigger asChild>
<TooltipTrigger asChild>
<Button size={"icon"} variant={"ghost"}>
{icon}
</Button>
</TooltipTrigger>
</PopoverTrigger>
<TooltipContent
side="right"
className="bg-secondary font-semibold text-foreground"
>
<p>{title}</p>
<TooltipArrow className="fill-secondary" />
</TooltipContent>
</Tooltip>
<PopoverContent side="right">
<div>{children}</div>
<PopoverArrow className="fill-popover" />
</PopoverContent>
</Popover>
</TooltipProvider>