roi-blog

ハンバーガーメニュー サイドバー 動くやつあるある

当サイトにもある、ハンバーガーメニューの実装について紹介します

この手の UI は広く知られ、実装方法とかいくらでもあると思いますが、当サイトの例を紹介します。

まずハンバーガーメニュー自体の描画です。

/**
 * ハンバーガーメニューSVGのDOM
 */
const HamburgerMenuDOM = () => {
  return (
    <svg viewBox="0 0 24 24" className="h-6 w-6 fill-current">
      <path
        fillRule="evenodd"
        clipRule="evenodd"
        d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"
      ></path>
    </svg>
  );
};

そしてサイドバー含めたヘッダー全体のコンポーネントです

export const Title = (title: string, path: string = "") => {
  const [isOpen, setIsOpen] = useState(false);

  useEffect(() => {
    if (isOpen) {
      document.body.style.overflow = "hidden";
    } else {
      document.body.style.overflow = "unset";
    }
  }, [isOpen]);

  // 左サイドバーの領域
  const LeftSideBar = (
    links: {
      url: string;
      text: string;
    }[],
    isOpen: boolean
  ) => {
    return (
      <div
        className={`transform top-0 left-0 w-64 fixed h-full overflow-auto ease-in-out transition-all duration-300 z-50 ${
          isOpen ? "translate-x-0" : "-translate-x-full"
        } bg-gray-700`}
      >
        <div className="flex flex-col space-y-2 p-4">
          <div className="flex items-center pb-4">
            <button
              className="text-gray-500 hover:text-gray-50 focus:outline-none focus:text-gray-50 hover:bg-gray-800 rounded-full p-1"
              aria-label="toggle menu"
              onClick={() => setIsOpen(!isOpen)}
            >
              <HamburgerMenuDOM />
            </button>
          </div>
          {links.map((link) => {
            return (
              <a
                href={link.url}
                className="text-gray-50 hover:underline transition duration-300 px-5 py-2  rounded-xl text-center hover:bg-gray-300 hover:text-gray-800"
                key={link.url}
              >
                <span style={{ display: "inline-block" }}>{link.text}</span>
              </a>
            );
          })}
        </div>
      </div>
    );
  };

  return (
    <>
      <h2 className="text-center m-0 p-4 relative text-2xl font-bold shadow-lg flex bg-gray-800 text-gray-500">
        <div className="flex items-center">
          <button
            className="text-gray-500 hover:text-gray-50 hover:bg-gray-900 focus:outline-none focus:text-gray-50 rounded-full p-1"
            aria-label="toggle menu"
            onClick={() => setIsOpen(!isOpen)}
          >
            <HamburgerMenuDOM />
          </button>
        </div>
        <Link
          href={path}
          className="hover:text-gray-100 transition duration-300 ml-auto"
        >
          <span style={{ display: "inline-block" }}>{title}</span>
        </Link>
      </h2>

      <div
        className={`fixed inset-0 bg-black bg-opacity-50 z-50 transition-opacity ${
          isOpen ? "opacity-100" : "opacity-0 pointer-events-none"
        }`}
        onClick={() => setIsOpen(false)}
      ></div>

      {/* ハンバーガーメニュー押下時に表示される左サイドバー */}
      {LeftSideBar(links, isOpen)}
    </>
  );
};

カスみたいなコードですね ❗️

関連記事