Multiple Popovers and incorrect positioning help #749
Replies: 2 comments
-
You are re-using the same state for each element: let [referenceElement, setReferenceElement] = useState()
let [popperElement, setPopperElement] = useState()
let { styles, attributes } = usePopper(referenceElement, popperElement); You want this to be unique per Popover. function MyPopover() {
let [referenceElement, setReferenceElement] = useState();
let [popperElement, setPopperElement] = useState();
let { styles, attributes } = usePopper(referenceElement, popperElement);
return (
<Popover className="mb-20">
<Popover.Button ref={setReferenceElement}>
<span>{popover.label}</span>
<ChevronDownIcon
className={`
${open ? "transform -rotate-180" : ""}
ml-2 h-5 w-5 text-orange-300 group-hover:text-opacity-80 transition ease-in-out duration-150`}
aria-hidden="true"
/>
</Popover.Button>
<Popover.Panel
ref={setPopperElement}
style={styles.popper}
{...attributes.popper}
>
<div className="overflow-visible rounded-xl shadow-lg ring-1 ring-black ring-opacity-5">
<div className="grid gap-8 grid-cols-1 bg-clip-padding backdrop-filter backdrop-blur-lg bg-gray-50 bg-opacity-75 p-7 rounded-xl">
<a href="#">{popover.label} - Sub Item 1</a>
<a href="#">{popover.label} - Sub Item 2</a>
<a href="#">{popover.label} - Sub Item 3</a>
<a href="#">{popover.label} - Sub Item 4</a>
</div>
</div>
</Popover.Panel>
</Popover>
);
} Now that this is scoped per Popover, you can use it: import React, { useState, Fragment } from "react";
import { Popover } from "@headlessui/react";
import { usePopper } from "react-popper";
import { ChevronDownIcon } from "@heroicons/react/solid";
const popovers = [
{
id: "1",
label: "Popover 1",
},
{
id: "2",
label: "Popover 2",
},
{
id: "3",
label: "Popover 3",
},
];
function MenuPopover() {
return (
<Fragment>
{popovers.map((popover) => (
<MyPopover key={popover.id} />
))}
</Fragment>
);
}
export default MenuPopover; You probably want to make the children of the |
Beta Was this translation helpful? Give feedback.
-
Thank you for the helpful reply. My initial example code was just to see how multiple instances can be possible but I would like to achieve something similar to below.
I guess I am looking for the best/most minimal/leanest way of achieving this with one graphql query and least components as possible. import { graphql, useStaticQuery } from 'gatsby'
import React, { Fragment } from 'react'
import { Popover, Transition } from '@headlessui/react';
import { usePopper } from 'react-popper';
import { ChevronDownIcon } from '@heroicons/react/solid';
function Menu() {
const { wpSiteMenuPrimary } = useStaticQuery(graphql`
query wordpressHeaderMenu {
wpSiteMenuPrimary: allWpMenuItem(filter: {locations: {in: PRIMARY}}, sort: {order: ASC, fields: order}) {
nodes {
id
label
path
url
parentId
order
childItems {
nodes {
id
label
path
url
parentId
order
childItems {
nodes {
id
label
path
url
parentId
order
}
}
}
}
}
}
}
`);
// WP Menu
const menuItems = wpSiteMenuPrimary.nodes
? wpSiteMenuPrimary.nodes.filter(menuItem => menuItem.parentId === null) // Filter only parents in Menu
: null
return (
<div className="flex px-2 lg:px-0">
<div className="hidden lg:ml-6 lg:flex lg:space-x-8">
{menuItems.map(menuItem => (
menuItem.childItems.nodes.length <= 0 ?
<a
key={menuItem.id}
href={menuItem.url}
className={`
${menuItem.url == location.pathname ? 'border-indigo-500' : 'border-transparent'}
text-gray-900 inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium`}
>
{menuItem.label}
</a>
:
<Popover key={menuItem.id}
className={`
${menuItem.url == location.pathname ? 'border-indigo-500' : 'border-transparent'}
text-gray-900 inline-flex items-center pt-1 border-b-2 text-sm font-medium`}
>
{({ open }) => (
<>
<Popover.Button
ref={setReferenceElement}
className={`
${open ? '' : 'text-opacity-90'}
border-indigo-500 text-gray-900 inline-flex items-center text-sm font-medium`}
>
<span>{menuItem.label}</span>
<ChevronDownIcon
className={`
${open ? 'transform -rotate-180' : ''}
ml-2 h-5 w-5 text-orange-300 group-hover:text-opacity-80 transition ease-in-out duration-150`}
aria-hidden="true"
/>
</Popover.Button>
<Transition
enter="transition ease-out duration-200"
enterFrom="opacity-0 translate-y-1"
enterTo="opacity-100 translate-y-0"
leave="transition ease-in duration-150"
leaveFrom="opacity-100 translate-y-0"
leaveTo="opacity-0 translate-y-1"
>
<Popover.Panel
ref={setPopperElement}
style={styles.popper}
{...attributes.popper}
className={`
${menuItem.childItems.nodes.length < 6 ? 'lg:max-w-xs' : ''}
${menuItem.childItems.nodes.length >= 6 ? 'lg:max-w-sm' : ''}
${menuItem.childItems.nodes.length >= 12 ? 'lg:max-w-xl' : ''}
${menuItem.childItems.nodes.length >= 18 ? 'lg:max-w-3xl' : ''}
z-10 overflow-visible`}
>
<div className="overflow-visible rounded-xl shadow-lg ring-1 ring-black ring-opacity-5">
<div className={`
${menuItem.childItems.nodes.length < 6 ? 'lg:grid-cols-1' : ''}
${menuItem.childItems.nodes.length >= 6 ? 'lg:grid-cols-2' : ''}
${menuItem.childItems.nodes.length >= 12 ? 'lg:grid-cols-3' : ''}
${menuItem.childItems.nodes.length >= 18 ? 'lg:grid-cols-4' : ''}
grid gap-8 bg-clip-padding backdrop-filter backdrop-blur-lg bg-gray-50 bg-opacity-75 p-7 rounded-xl`}>
{menuItem.childItems.nodes && menuItem.childItems.nodes.map(subMenuItem => (
subMenuItem.childItems.nodes.length <= 0 ?
<a
key={subMenuItem.id}
href={subMenuItem.url}
className="h-8 flex items-center p-2 pt-3 pb-0 -m-3 transition duration-150 ease-in-out rounded-lg hover:bg-gray-50 outline-none"
>
<div className="ml-0">
<p className={`
${subMenuItem.url == location.pathname ? 'border-indigo-500' : 'border-transparent'}
text-sm font-medium text-gray-900 items-center leading-7 pt-1 border-b-2`}>
{subMenuItem.label}
</p>
</div>
</a>
:
<Popover key={subMenuItem.id} className="relative h-8 flex items-center p-2 pt-0 pb-0 -m-3 transition duration-150 ease-in-out rounded-lg hover:bg-gray-50 outline-none">
{({ open }) => (
<>
<Popover.Button
className={`
${open ? '' : 'text-opacity-90'}
${subMenuItem.url == location.pathname ? 'border-indigo-500' : 'border-transparent'}
text-sm font-medium text-gray-900 inline-flex items-center leading-7 pt-1 border-b-2`}
>
<span>{subMenuItem.label}</span>
<ChevronDownIcon
className={`
${open ? 'transform -rotate-180' : ''}
ml-2 h-5 w-5 text-orange-300 group-hover:text-opacity-80 transition ease-in-out duration-150`}
aria-hidden="true"
/>
</Popover.Button>
<Transition
enter="transition ease-out duration-200"
enterFrom="opacity-0 translate-y-1"
enterTo="opacity-100 translate-y-0"
leave="transition ease-in duration-150"
leaveFrom="opacity-100 translate-y-0"
leaveTo="opacity-0 translate-y-1"
>
<Popover.Panel className={`
${subMenuItem.childItems.nodes.length < 6 ? 'lg:max-w-xs' : ''}
${subMenuItem.childItems.nodes.length >= 6 ? 'lg:max-w-sm' : ''}
${subMenuItem.childItems.nodes.length >= 12 ? 'lg:max-w-xl' : ''}
${subMenuItem.childItems.nodes.length >= 18 ? 'lg:max-w-3xl' : ''}
absolute z-10 w-screen max-w-sm px-4 mt-3 transform -translate-x-1/2 left-1/2 sm:px-0 top-5`}>
<div className="overflow-hidden rounded-xl shadow-lg ring-1 ring-black ring-opacity-5">
<div className={`
${subMenuItem.childItems.nodes.length < 6 ? 'lg:grid-cols-1' : ''}
${subMenuItem.childItems.nodes.length >= 6 ? 'lg:grid-cols-2' : ''}
${subMenuItem.childItems.nodes.length >= 12 ? 'lg:grid-cols-3' : ''}
${subMenuItem.childItems.nodes.length >= 18 ? 'lg:grid-cols-4' : ''}
relative grid gap-8 bg-clip-padding backdrop-filter backdrop-blur-lg bg-gray-50 bg-opacity-95 p-7`}>
{subMenuItem.childItems.nodes && subMenuItem.childItems.nodes.map(childSubMenuItem => (
<a
key={childSubMenuItem.id}
href={childSubMenuItem.url}
className="h-8 flex items-center p-2 pt-3 pb-0 -m-3 transition duration-150 ease-in-out rounded-lg hover:bg-gray-50 outline-none"
>
<div className="ml-0">
<p className={`
${childSubMenuItem.url == location.pathname ? 'border-indigo-500' : 'border-transparent'}
text-sm font-medium text-gray-900 items-center leading-7 pt-1 border-b-2`}>
{childSubMenuItem.label}
</p>
</div>
</a>
))}
</div>
</div>
</Popover.Panel>
</Transition>
</>
)}
</Popover>
))}
</div>
</div>
</Popover.Panel>
</Transition>
</>
)}
</Popover>
))}
</div>
</div>
);
}
export default Menu; |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Hello,
I am trying to use multiple popovers for looping through menu items & and their children for example.
Using example code taken from https://headlessui.dev/react/popover#positioning-the-panel.
Is there a way to use multiple popovers while retaining the correct position for each? All Popovers appear in the same position as the last.
floating-ui/floating-ui#1348
Beta Was this translation helpful? Give feedback.
All reactions