haveman
haveman

Reputation: 393

Changing Popover internal state - Headless UI

How do i change the internal state of the Popover with a function outside the component: Like the openPopover function i created below.

const openPopover = () => {
    setPopoverOpen(true) // Example..
}

<Popover>
  {({open}: {open: boolean}) => {
    // How do i change the open state here from outside the Popover.

    return (
      <>
        <Popover.Button>
          Test
        </Popover.Button>

        {open && (
          <Popover.Panel static>
            Test
          </Popover.Panel>
        )}   
      </>
    )
  }}
</Popover>

Upvotes: 6

Views: 2549

Answers (2)

Sabareesh S
Sabareesh S

Reputation: 1

Here's a workaround, remove the open state condition and manipulate the static prop

<Popover>
  {({open}: {open: boolean}) => {
    useEffect(() => {
      setIsPopoverOpen(open)
    }, [open]);

    return (
      <>
        <Popover.Button>
          Test
        </Popover.Button>
   
          <Popover.Panel static> // manipulate this static prop
            Test
          </Popover.Panel>  
      </>
    )
  }}
</Popover>

Upvotes: 0

Badal Saibo
Badal Saibo

Reputation: 3675

Popover manages open state internally and doesn't expose a way to change this.

To keep track of the open state however, you could use a useEffect inside the render prop.

const [isPopoverOpen, setIsPopoverOpen] = useState(false);

<Popover>
  {({open}: {open: boolean}) => {
    useEffect(() => {
      setIsPopoverOpen(open)
    }, [open]);

    return (
      <>
        <Popover.Button>
          Test
        </Popover.Button>,
   
        {open && (
          <Popover.Panel static>
            Test
          </Popover.Panel>
        )}   
      </>
    )
  }}
</Popover>

The toggling behavior is being handled by <Popover.Button> component. Alternatively, Popover and Popover.Panel exposes a close() method to close the popover. You could always use Portals to make the component available in parent for handling either toggling or executing the close() method.

import { createPortal } from 'react-dom';

<Popover>
  {({ open, close }) => {
    return (
      <>
       {createPortal(
        <Popover.Button>
          Toggle popover
        </Popover.Button>,
        // html node where we will position this button
       )}

        {open && (
          <Popover.Panel static>
            Test
          </Popover.Panel>
        )}

       {createPortal(
         <button onClick={close()}>
            Close Popover
         </button>,
         // html node where we will position this close button
        )}
      </>
    )
  }}
</Popover>

Upvotes: 2

Related Questions