I’m using react typescript for the first time, and I implemented outside click event. I’m running into a problem where whenever i click on the active or currently selected component, it seems to trigger the onclick and outside click event.
Attached here i the GIF to better understand my problem.
when the selected component is clicked, it set as active, and when i click it again it seems like it triggers the outside click then trigger the click event.
here is my code implementation.
import { Button } from "@/components/ui/button";
import {
Menubar,
MenubarContent,
MenubarItem,
MenubarMenu,
MenubarTrigger,
} from "@/components/ui/menubar";
import { MapPin, MoreVertical, PinOff } from "lucide-react";
import { HtmlHTMLAttributes, useState } from "react";
import OutsideClick from "outsideclick-react";
import { Props } from "@/utilities/navigation_props";
interface DocumentCardProps extends Props, HtmlHTMLAttributes<HTMLDivElement> {
data: DateType,
onSelectActive: (id: number|null) => void,
}
type DateType = {
id: number
}
const DocumentCard = ({
data,
active,
onSelectActive,
...props
}: DocumentCardProps) => {
return (
<OutsideClick
onOutsideClick={() => {
onSelectActive(null)
console.log(active)
}}
ignoreElement={[".menubarEl"]}
className="pointer-events-none"
onClick={(e) => {
e.stopPropagation()
onSelectActive(data.id)
}}
>
<div
{...props}
className={`h-56 p-2 flex flex-col rounded-xl cursor-default pointer-events-auto
${active == data.id ? "dark:bg-green-400/50 bg-green-400/50" : "hover:bg-tertiary"}`}
>
<div className="bg-tertiary grow rounded-lg overflow-hidden pointer-events-none">
<img src="https://picsum.photos/400" alt="" className="" />
</div>
<div className="shrink-0 py-2 text-sm font-medium px-0.5 flex items-center">
<div className="grow">
<div className={`${active == data.id ? "dark:text-emerald-200" : ""}`}>
Document title
</div>
<div
className={`opacity-70 font-normal text-xs ${active == data.id ? "dark:text-emerald-300" : ""
}`}
>
Document{">"}path{">"}name
</div>
</div>
<div>
<Menubar className="!border-none !bg-transparent !p-0">
<MenubarMenu>
<MenubarTrigger className="!px-0 focus:!bg-transparent data-[state=open]:!bg-transparent !p-0 !rounded-full ring-1">
<Button
asChild
variant={"ghost"}
size={"iconxs"}
className={`hover:dark:border-white/10 !rounded-full border hover:border-gray-300/60 dark:hover:bg-white/5 border-transparent`}
>
<div>
<MoreVertical className="h-4 w-4" />
</div>
</Button>
</MenubarTrigger>
<MenubarContent className="ring-1 ring-inset menubarEl" align="end" alignOffset={20} sideOffset={-15}>
<MenubarItem>
<PinOff className="w-5 h-5" strokeWidth={1.7} />
<div className="ml-3">Unpin</div>
</MenubarItem>
<MenubarItem>
<MapPin className="w-5 h-5" strokeWidth={1.7} />
<div className="ml-3">Track</div>
</MenubarItem>
</MenubarContent>
</MenubarMenu>
</Menubar>
</div>
</div>
</div>
</OutsideClick>
);
};
function Pinned() {
const [active, setActive] = useState<number|null>(null)
const documents = [
{ id: 1 },
{ id: 2 },
{ id: 3 },
{ id: 4 },
{ id: 5 },
{ id: 6 },
{ id: 7 },
];
return (
<div className="grid grid-cols-[repeat(auto-fill,minmax(17rem,1fr))] gap-1">
{documents.map((item, index) => (
<DocumentCard
key={index}
data={item}
active={active}
onSelectActive={(id) => {
setActive(id)
}}
/>
))}
</div>
);
}
export default Pinned;
I’m using outsideclick-react, and shadcn for the popover
2
Answers
After implementing various ways for the problem, I came up with a solution by implementing the outsideclick on the parent component. I noticed that when i click outside the DocumentCard component, other DocumentCard components triggers an outsideclick which causes the problem. This was the revision i made:
So, the revised implementation is to put the outsideclick in the parent component ensuring that it only triggers once.
Stop event propagation to parent , use preventDefault()/stopPropagation()