React×Tailwindで作るハンバーガーメニュー!

今回は、React(TypeScript)とTailwindでハンバーガーメニューを作ってみました。
個人開発でTailwindを使ってフロント部分を作っているのですが、素のCSSであれば簡単にできていたことが意外とTailwindを使うとどうやるんだっけということが多いので、まとめておきます。

本記事の信頼性

30歳から異業種への転職をして、Shopify Experts企業で1年半ほどフルリモートで勤務していました。
現在は名古屋の自社開発企業のフロントエンドエンジニアしています。フリーランスとしても活動しています。

スポンサーリンク

目次

最終的なコード

あわせて読みたい
tailwind drawer-menu - CodeSandbox tailwind drawer-menu by okahanako09875 using react, react-dom, react-scripts
実装コード(クリックするとコードが表示されます)
import './styles.css';
import React, { useState } from 'react';

export default function App() {
  const [openMenu, setOpenMenu] = useState(false);

  const handleMenuOpen = () => {
    setOpenMenu(!openMenu);
  };

  return (
    <div className="App">
      <div className="container mx-auto px-3">
        <header className="flex justify-between py-3">
          <h1>ロゴ</h1>

          {/* humbergerbutton */}
          <button onClick={handleMenuOpen} type="button" className="z-10 space-y-2">
            <div
              className={
                openMenu
                  ? 'w-8 h-0.5 bg-gray-600 translate-y-2.5 rotate-45 transition duration-500 ease-in-out'
                  : 'w-8 h-0.5 bg-gray-600 transition duration-500 ease-in-out'
              }
            />
            <div
              className={
                openMenu
                  ? 'opacity-0 transition duration-500 ease-in-out'
                  : 'w-8 h-0.5 bg-gray-600 transition duration-500 ease-in-out'
              }
            />
            <div
              className={
                openMenu
                  ? 'w-8 h-0.5 bg-gray-600 -rotate-45 transition duration-500 ease-in-out'
                  : 'w-8 h-0.5 bg-gray-600 transition duration-500 ease-in-out'
              }
            />
          </button>

          {/* nav */}
          <nav
            className={
              openMenu
                ? 'text-left fixed bg-slate-50 right-0 top-0 w-8/12 h-screen flex flex-col justify-start pt-8 px-3 ease-linear duration-300'
                : 'fixed right-[-100%] ease-linear duration-300'
            }
          >
            <ul className="mt-6">
              <li className="">
                <a href="https://okalog.info/" className="py-2 inline-block">
                  ABOUT
                </a>
              </li>
              <li className="">
                <a href="https://okalog.info/" className="py-2 inline-block">
                  WORKS
                </a>
              </li>
              <li className="">
                <a href="https://okalog.info/" className="py-2 inline-block">
                  PEOPLE
                </a>
              </li>
              <li className="">
                <a href="https://okalog.info/" className="py-2 inline-block">
                  CONTACT
                </a>
              </li>
            </ul>
          </nav>
        </header>

        {/* ここ以下はメインビジュアル用のコード */}
        <main>
          {/* MainVisual */}
          <div className="mt-10">
            <div className="mx-auto w-full">
              <img
                src="https://okalog.info/wp-content/uploads/sample/scenery/scenery_01.jpg"
                alt=""
                className="w-full rounded-3xl object-cover"
              />
            </div>
          </div>
        </main>

      </div>
    </div>
  );
}

実装方法

今回はReact(TypeScript)とTailwindが動作する環境は既にある前提で進めていきます。

ヘッダーを作成する

まずは、ヘッダー部分を作成します。
シンプルにロゴとハンバーガーメニューだけが存在するヘッダーとします。

ハンバーガーメニューは

<header className="flex justify-between py-3">
  <h1>ロゴ</h1>

  <button type="button" className="z-10 space-y-2">
    <div className="w-8 h-0.5 bg-gray-600" />
    <div className="w-8 h-0.5 bg-gray-600" />
    <div className="w-8 h-0.5 bg-gray-600" />
  </button>
</header>

オープン・クローズの挙動を作成する

次に、ハンバーガーメニューをクリックしたときにナビゲーションが表示される部分をReactで実装していきます。

useStateを使って表示・非表示を切り替えます。
button要素にonClick={handleMenuOpen}を付与して、true/falseを切り替えができるようにします。
次に、openMenutrue/falseのときにCSSを出し分けを行います。

三項演算子を使って実現することができます。

{openMenu ? "trueのとき" : "falseのとき" }

ハンバーガーメニューとナビゲーション要素で使用しています。

function App() {
  const [openMenu, setOpenMenu] = useState(false);
  const handleMenuOpen = () => {
    setOpenMenu(!openMenu);
  };

  return (
    <div className="App">
      <div className="container mx-auto px-3">
        <header className="flex justify-between py-3">
          <h1>ロゴ</h1>

          {/* humbergerbutton */}
          <button onClick={handleMenuOpen} type="button" className="z-10 space-y-2">
            <div className={openMenu ? 'w-8 h-0.5 bg-gray-600 translate-y-2.5 rotate-45' : 'w-8 h-0.5 bg-gray-600'} />
            <div className={openMenu ? 'opacity-0' : 'w-8 h-0.5 bg-gray-600'} />
            <div className={openMenu ? 'w-8 h-0.5 bg-gray-600 -rotate-45' : 'w-8 h-0.5 bg-gray-600'} />
          </button>

          {/* nav */}
          <nav
            className={
              openMenu
                ? 'text-left fixed bg-slate-50 right-0 top-0 w-8/12 h-screen flex flex-col justify-start pt-8 px-3'
                : 'fixed right-[-100%]'
            }
          >
            <ul className="mt-6">
             // 省略
            </ul>
          </nav>
        </header>
      </div>
    </div>
  );
}
実装後のイメージ

アニメーションをつける

現状ですと、すぐに切り替わってしまうのでCSSのtransitionを付与します。
参考→ Transition Property


export default function App() {
  const [openMenu, setOpenMenu] = useState(false);

  const handleMenuOpen = () => {
    setOpenMenu(!openMenu);
  };

  return (
    <div className="App">
      <div className="container mx-auto px-3">
        <header className="flex justify-between py-3">
          <h1>ロゴ</h1>

          {/* humbergerbutton */}
          <button
            onClick={handleMenuOpen}
            type="button"
            className="z-10 space-y-2"
          >
            <div
              className={
                openMenu
                  ? "w-8 h-0.5 bg-gray-600 translate-y-2.5 rotate-45 transition duration-500 ease-in-out"
                  : "w-8 h-0.5 bg-gray-600 transition duration-500 ease-in-out"
              }
            />
            <div
              className={
                openMenu
                  ? "opacity-0 transition duration-500 ease-in-out"
                  : "w-8 h-0.5 bg-gray-600 transition duration-500 ease-in-out"
              }
            />
            <div
              className={
                openMenu
                  ? "w-8 h-0.5 bg-gray-600 -rotate-45 transition duration-500 ease-in-out"
                  : "w-8 h-0.5 bg-gray-600 transition duration-500 ease-in-out"
              }
            />
          </button>

          {/* nav */}
          <nav
            className={
              openMenu
                ? "text-left fixed bg-slate-50 right-0 top-0 w-8/12 h-screen flex flex-col justify-start pt-8 px-3 ease-linear duration-300"
                : "fixed right-[-100%] ease-linear duration-300"
            }
          >
            <ul className="mt-6">
              //省略
            </ul>
          </nav>
        </header>

        {/* ここ以下はメインビジュアル用のコード */}
        <main>
          {/* MainVisual */}
          <div className="mt-10">
            <div className="mx-auto w-full">
              <img
                src="https://okalog.info/wp-content/uploads/sample/scenery/scenery_01.jpg"
                alt=""
                className="w-full rounded-3xl object-cover"
              />
            </div>
          </div>
        </main>

      </div>
    </div>
  );
}

最終的にはこの状態になります。

まとめ

Tailwindですが、どんあクラスが用意されているのかを調べるのが毎回時間かかってしまいますがやっていれば慣れてくるのかなーという思いで触っております。

今後もTailwindを使った実装をしていく予定ですよので、学んだことがあればブログにして発信していきます。

こちらオススメのUdemyの学習教材です!^^

スポンサーリンク

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!
目次