thomazmz
thomazmz

Reputation: 192

Two or more buttons triggering the same Material-UI Popper element

So, I got into a situation where I need to trigger the same Material-UI <Popper /> component from multiple different clickable elements.

As is it is described on the Popper component API on Material-UI website, when calling the Popper component you might want to pass a property named anchorEl which defines where the popper will be positioned on the canvas. My intention is for that anchorEl to always be the same, thus the popper will always open at the same position on the UI.

Most of the examples on Material-UI documentation suggest the following approach for using Popper:


const SimplePopper = () => {
  const [anchorEl, setAnchorEl] = React.useState(null);

  const handleClick = (event) => {
    setAnchorEl(anchorEl ? null : event.currentTarget);
  };

  const open = Boolean(anchorEl);

  return (
    <div>
      <button type="button" onClick={handleClick}>
        Toggle Popper
      </button>
      <Popper open={open} anchorEl={anchorEl}>
        <div className={classes.paper}>The content of the Popper.</div>
      </Popper>
    </div>
  );
}

The first problem with this usage is that your code depends on the handleClick function to be called for it to define the anchorEl state value.

The second problem is that, even if you have more than one button element calling the handleClick function, the value on event.currentTarget would vary and the Popper element would show up in different positions of the canvas.

So, the question is:

How could I have two or more buttons triggering the same <Popper /> element in a way it always renders under the same anchorEl.

Upvotes: 0

Views: 1987

Answers (1)

Arun Kumar Mohan
Arun Kumar Mohan

Reputation: 11915

One way to do it would be to add a ref to the anchor element and pass it to Popper and use a state variable to manage the popper open state. You can then toggle the open state when the trigger elements are clicked.

const App = () => {
  const anchorRef = useRef(null)
  const [open, setOpen] = useState(false)

  const handleClick = () => {
    setOpen(!open)
  }

  return (
    <>
      <Button onClick={handleClick}>Toggle Popper</Button>
      <Button onClick={handleClick} ref={anchorRef}>
        Toggle Popper
      </Button>

      <Popper open={open} anchorEl={anchorRef.current}>
        The content of the Popper.
      </Popper>
    </>
  )
}

CodeSandbox

Upvotes: 1

Related Questions