🪖

【React】MUIのPopoverとPopperの違いのメモ

2024/12/14に公開

ジャンルなしオンラインもくもく会 Advent Calendar 2024 - Adventar、14日目の記事です。

概要

MUIにはPopoverPopperという、ぱっと見で似たようなコンポーネントがあります。双方ともあるオブジェクトに対してポップアップを表示するようなものなのですが、今回はこの2つの違い等をメモ書きします。

前提

  • 使用したmuiのバージョンは6.2.0です。

基本的な実装

基本的な実装のやり方は双方ほぼ同様で、ポップアップを表示したいオブジェクトに対してアンカーを設定する感じです。以下はPopoverのサンプル実装です。

import React, { FC, useState } from "react";
import {
  Button,
  Popover,
  Typography,
} from "@mui/material";

export const PopperPopoverSample: FC = () => {
  const [popoverAnchorEl, setPopoverAnchorEl] =
    useState<HTMLButtonElement | null>(null);

  const handlePopoverClick = (event: React.MouseEvent<HTMLButtonElement>) => {
    setPopoverAnchorEl(event.currentTarget);
  };

  const handlePopoverClose = () => {
    setPopoverAnchorEl(null);
  };

  return (
    <>
      <Button variant="contained" onClick={handlePopoverClick}>
        Open Popover
      </Button>
      <Popover
        open={!!popoverAnchorEl}
        anchorEl={popoverAnchorEl}
        onClose={handlePopoverClose}
        anchorOrigin={{
          vertical: "bottom",
          horizontal: "left",
        }}
      >
        <Typography sx={{ p: 2 }}>The content of the Popover.</Typography>
      </Popover>
    </>
  );
};

主な違い

【Popover】

  • 動作としてはほぼモーダルです、ポップアップを表示した後モーダルと同様に画面がロックされます。
  • ポップアップ外をクリックすると、ポップアップは閉じられます。

【Popper】

  • ポップアップを表示した後も、画面はロックされません。
  • ポップアップ外をクリックしても、基本的にはポップアップは閉じられません。
  • ポップアップ外をクリックしたときに閉じたい場合は、Close material-ui popper when on clickAwayのstackoverflowの記事にように、一手間加える必要があります。以下がClickAwayListenerを使った時の実装サンプルです。
import React, { FC, useState } from "react";
import {
  Box,
  ClickAwayListener,
  Popper,
} from "@mui/material";

export const PopperPopoverSample: FC = () => {
  const [popperAnchorEl, setPopperAnchorEl] = useState<null | HTMLElement>(
    null
  );

  const handlePopperClick = (event: React.MouseEvent<HTMLElement>) => {
    setPopperAnchorEl(popperAnchorEl ? null : event.currentTarget);
  };

  const clickAwayPopperHandler = () => {
    if (popperAnchorEl) {
      setPopperAnchorEl(null);
    }
  };

  return (
    <div>
      <ClickAwayListener onClickAway={clickAwayPopperHandler}>
        <div>
          <button type="button" onClick={handlePopperClick}>
            Toggle Popper
          </button>
          <Popper open={!!popperAnchorEl} anchorEl={popperAnchorEl}>
            <Box sx={{ border: 1, p: 1, bgcolor: "background.paper" }}>
              The content of the Popper.
            </Box>
          </Popper>
        </div>
      </ClickAwayListener>
    </div>
  );
};

Discussion