【React】MantineUIで作るハンバーガーメニュー

はじめに

この記事の概要

こんにちは、株式会社TOKOSのスギタです!
今回はtailwindcssを用いてUIライブラリMantineを使いハンバーガーメニューを作成する方法を説明していきたいと思います。
Maneineについてわからない方は下記を参考にしてください!

【React】tailwindcssで作るMantineUIのMultiSelectコンポーネント

対象読者

  • Reactを用いたWEB制作、WEB開発を行っている方
  • tailwindcssを使用しながらUIライブラリを使用したい方

開発環境

  • React 18.0.28
  • Next.js13.2.3
  • TypeScript 4.9.5
  • Mantaine 6.0.13
  • day.js 1.11.8

下記参照内でフレームワークを選択してください。
今回はNext.jsで行っていきたいと思います!

完成予定

今回の完成予定は下記になります。

ハンバーガーメニューの実装

まずはメニューボタンから作成します。
メニューボタンですが、MantineUIから、Burgerコンポーネントを使用します。

import { Burger } from "@mantine/core"

const ExamplePage: NextPageWithLayout = () => {
 <header className="fixed z-20 flex w-full gap-y-2 bg-blue-500 p-4 text-white shadow">
      <div className="flex w-full max-w-[1366px] justify-between">
        <div className="flex w-full justify-between">
          <div>
            <Burger
              opened={false}
              color="#fff"
            />
          </div>
          <p className="flex w-full items-center justify-center text-xl font-bold">
            TOKOS.inc
          </p>
        </div>
      </div>
    </header>
}

Component propsのcolorで色の指定をしています。
まだ状態管理をしていないので、現状は動かないと思います。
ではここから状態管理を追加して、メニューを押した際のアニメーションを追加していきたいと思います。

import { Burger } from "@mantine/core"

const ExamplePage: NextPageWithLayout = () => {
 <header className="fixed z-20 flex w-full gap-y-2 bg-blue-500 p-4 text-white shadow">
      <div className="flex w-full justify-between">
        <div className="flex w-full justify-between">
          <div>
            <Burger
              opened={true}
              color="#fff"
            />
          </div>
          <p className="flex w-full items-center justify-center text-xl font-bold">
            TOKOS.inc
          </p>
        </div>
      </div>
    </header>
}

Component propsのopenedをtrueに変えるとバツになると思います。
このComponent propsのopenedが表示状態の管理をしていることがわかったと思います。
ではこのメニューを押した際にopenedの真偽値を切り替えていきたいので、Component propsのonClickで押した際の動作を追記していきます。

また、今回は複数のコンポーネントの状態管理をuseDisclosureというMantineのCustomHooksを使用していきます。

import { Burger } from "@mantine/core"
import { useDisclosure } from "@mantine/hooks"

const ExamplePage: NextPageWithLayout = () => {
const [isHamburgerOpened,{ toggle: hamburgerToggle },] = useDisclosure(false)
 <header className="fixed z-20 flex w-full gap-y-2 bg-blue-500 p-4 text-white shadow">
      <div className="flex w-full justify-between">
        <div className="flex w-full justify-between">
          <div>
            <Burger
              opened={isHamburgerOpened}
              onClick={hamburgerToggle}
              color="#fff"
            />
          </div>
          <p className="flex w-full items-center justify-center text-xl font-bold">
            TOKOS.inc
          </p>
        </div>
      </div>
    </header>
}

BurgerコンポーネントのonClickuseDisclosureのtoggle関数(hamburgerToggle)を渡します。またopenedに動作した関数によって切り替わった真偽値を渡すようにします。

CustomHooksのuseDisclosureですが
公式ドキュメントを見ると、真偽値の管理、open、close、toggleのハンドラーとonOpenとonCloseのコールバックがあります。今回はコールバック関数は使用しません

//公式のハンドラーの説明より
import { useDisclosure } from '@mantine/hooks';

function Demo() {
  const [opened, handlers] = useDisclosure(false);

  // openedをtrueに
  handlers.open();

  // openedをfalseに
  handlers.close();

  // openedの真偽値を反転
  handlers.toggle();
}

今回は、押した時にtoggle関数(hamburgerToggle)を使用して、真偽値の反転をしています。初期値はメニューが閉じた状態にしたいので、falseにしています。
これで、メニューボタンの実装は完了です。

次にMantineUiのDrawerコンポーネントを使用して、メニューの実装をします。

import { Burger,Drawer } from "@mantine/core"
import { useDisclosure } from "@mantine/hooks"

const ExamplePage: NextPageWithLayout = () => {
const [isHamburgerOpened,{ toggle: hamburgerToggle },] = useDisclosure(false)
 <header className="fixed z-20 flex w-full gap-y-2 bg-blue-500 p-4 text-white shadow">
      <div className="flex w-full justify-between">
        <div className="flex w-full justify-between">
          <div>
            <Burger
              opened={isHamburgerOpened}
              onClick={hamburgerToggle}
              color="#fff"
            />
       <Drawer
              opened={true}
              zIndex={0}
              withCloseButton={false}
              classNames={{
                body: "p-0",
                inner: "w-[380px]",
              }}
            >
              <div className="px-4 pt-[78px] font-bold">
                <p className="mb-4">マイページ</p>
                <p className="mb-4">ログアウト</p>
                <p>ホーム</p>
              </div>
            </Drawer>
          </div>
          <p className="flex w-full items-center justify-center text-xl font-bold">
            TOKOS.inc
          </p>
        </div>
      </div>
    </header>
}

まずはDrawerコンポーネントをMantine/coreから呼び出します。
ヘッダーより下にしたいので、Component propsのzIndexを0にします。
今回メニューを閉じるボタンはDrawerが行っているので、Component propsのwithCloseButtonはfalseにします(デフォルトがtrue)
Component propsのclaseNamesでデフォルトのpaddingを消し、メニューの幅を指定しています。

コンポーネントのデフォルトのcssを全て無くしたい場合

デフォルトで当たっているcssを全て無くしたい場合はpropsでunstyledを渡すとデフォルトのcssはなくなります。

ここから、開く処理と閉じる処理を追記します。

import { Burger,Drawer } from "@mantine/core"
import { useDisclosure } from "@mantine/hooks"

const ExamplePage: NextPageWithLayout = () => {
const [isHamburgerOpened,{ close: hamburgerClose,toggle: hamburgerToggle },] = useDisclosure(false)
 <header className="fixed z-20 flex w-full gap-y-2 bg-blue-500 p-4 text-white shadow">
      <div className="flex w-full justify-between">
        <div className="flex w-full justify-between">
          <div>
            <Burger
              opened={isHamburgerOpened}
              onClick={hamburgerToggle}
              color="#fff"
            />
       <Drawer
              opened={isHamburgerOpened}
              onClose={hamburgerClose}
              zIndex={0}
              withCloseButton={false}
              classNames={{
                body: "p-0",
                inner: "w-[380px]",
              }}
            >
              <div className="px-4 pt-[78px] font-bold">
                <p className="mb-4">マイページ</p>
                <p className="mb-4">ログアウト</p>
                <p>ホーム</p>
              </div>
            </Drawer>
          </div>
          <p className="flex w-full items-center justify-center text-xl font-bold">
            TOKOS.inc
          </p>
        </div>
      </div>
    </header>
}

useDisclosureにcloseハンドラーの追記とopenedに管理されている真偽値を渡し、Drawerが閉じる際に発火する関数としてuseDisclosureのcloseハンドラーを渡します。そうすることにより、メニューが開く際にisHamburgerOpenedがtrue、メニューが閉じた際にisHamburgerOpenedがfalseにという切り替えが可能になります。

さいごに

今回はMantineのHamburgerコンポーネントとDrawerコンポーネントそして、CustomHooksのuseDisclosureを使用しました。
やはりかなり簡単に実装できるかなと思いました。スクラッチで書こうとすると、overlayの箇所の動作や細かいアニメーションを考えるとかなり大変なので、こういう実装はUIライブラリに頼るのも手なのかなと感じます。