tailwind-hamburger-menu

【コピペだけ!】Tailwind & Next.js(React) ハンバーガーメニュー完全レスポンシブ対応

前回のSassを使ったハンバーガーメニューUIの記事はこちら⬇︎

今回の記事はコピペするだけで、完全レスポンシブ対応のハンバーガーメニューのコードを紹介。
Next.js(React) & Tailwind CSS を使っていて、TypeScript の tsx ファイルにも対応しています。

この記事のコードを使うことで、簡単にハンバーガーメニューを実装できるかと思います。

デモサイトURL

注意:これらのコードは 2024年7月の時点でのコードです。(下記機能がプロジェクトに沿う場合のみお使いください。)

このハンバーガーメニューの機能一覧です:

  • 完全レスポンシブ対応
  • 現在のパスにリンクに背景色が付く
  • メニュー外をクリックするとメニューが閉じる

使用したライブラリー

  • Tailwind CSSのみ

ファイル構成

app
  --  page.tsx
  --  Hamburger.tsx
  --  NavLinks

各ファイルのコード

page.tsx
"use client";
import Link from "next/link";
import NavLinks from "./NavLinks";
import Hamburger from "./Hamburger";

const Header = () => {
  return (
    <header
      className={`bg-black text-white py-2 max-[480px]:py4 max-[480px]:px-4 px-6 z-10`}
    >
      <nav className="max-w-[1080px] mx-auto flex justify-between items-center max-[899px]:hidden">
        <Link href="/">
          <div
            className="textShadow_wt text-[2.2rem] font-bold text-nowrap max-[1000px]:text-[1.8rem] 
          hover:opacity-70 transition-all duration-300"
          >
            LOGO
          </div>
        </Link>
        <NavLinks />
      </nav>
      <Hamburger />
    </header>
  );
};

export default Header;

Hamburger.tsx のコード
"use client";
import { useState } from "react";
import Link from "next/link";
import NavLinks from "./NavLinks";

const Hamburger = () => {
  const [isMenuOpen, setIsMenuOpen] = useState(false);
  return (
    <nav className="relative z-10 pr-8 pl-2 py-2 flex justify-between items-center text-slate-950 min-[900px]:hidden ">
      <Link href="/">
        <div className="text-3xl font-bold leading-none">
          <div
            className="textShadow_wt mt-4 text-white font-bold text-nowrap max-[1000px]:text-[2.4rem] 
          max-[768px]:text-[2rem] max-[768px]:mt-2 max-[480px]:text-[1.7rem] max-[480px]:mt-1 "
          >
            LOGO
          </div>
        </div>
      </Link>
      <button
        className="navbar-burger flex items-center text-white p-3 flex-row-reverse flex-grow"
        onClick={() => setIsMenuOpen(!isMenuOpen)}
      >
        <svg
          className="block h-6 w-6 fill-current"
          viewBox="0 0 20 20"
          xmlns="http://www.w3.org/2000/svg"
        >
          <title>Mobile menu</title>
          <path d="M0 3h20v2H0V3zm0 6h20v2H0V9zm0 6h20v2H0v-2z"></path>
        </svg>
      </button>
      <div
        className={`${isMenuOpen ? "flex" : "hidden"} absolute top-1/2 left-1/2 transform -translate-y-1/2 -translate-x-1/2 lg:flex lg:mx-auto lg:items-center lg:w-auto lg:space-x-6`}
      ></div>
      {isMenuOpen && (
        <div className="navbar-menu relative z-50">
          <div
            className="navbar-backdrop fixed inset-0 bg-neutral-800 opacity-75"
            onClick={() => setIsMenuOpen(false)}
          ></div>
          <div className="fixed top-0 left-0 bottom-0 flex flex-col w-4/6 max-w-sm py-6 px-6 bg-neutral-950/90 overflow-y-auto">
            {/* Logo & Close button */}
            <div className="flex items-center mb-8">
              <Link href="/">
                <div className="mr-auto text-3xl font-bold leading-none">
                  <div className="textShadow_wt text-white text-[2.2rem] font-bold text-nowrap max-[1000px]:text-[1.4rem] ">
                  LOGO
                  </div>
                </div>
              </Link>
              <button
                className="navbar-close ml-14"
                onClick={() => setIsMenuOpen(false)}
              >
                <svg
                  className="h-6 w-6 text-gray-400 cursor-pointer hover:text-gray-500"
                  xmlns="http://www.w3.org/2000/svg"
                  fill="none"
                  viewBox="0 0 24 24"
                  stroke="currentColor"
                >
                  <path d="M6 18L18 6M6 6l12 12"></path>
                </svg>
              </button>
            </div>
            <div>
              <NavLinks setIsMenuOpen={setIsMenuOpen} />
            </div>
          </div>
        </div>
      )}
    </nav>
  );
};

export default Hamburger;
NavLinks.tsx のコード
"use client";
import Link from "next/link";
import { usePathname } from "next/navigation";

type PropsType = {
  propClass?: string;
  setIsMenuOpen?: (arg0: boolean) => void;
};

const NavLinks = ({ propClass, setIsMenuOpen }: PropsType) => {
  const currentPath = usePathname();

  const links = [
    { label: "HOME", href: "/" },
    { label: "ABOUT", href: "/about" },
    { label: "CONTACT", href: "/contact" },
    { label: "SONGS", href: "/songs" },
    { label: "MERCH", href: "/merch" },
    { label: "ADMIN", href: "/admin", admin: true },
  ];

  return (
    <div
      className={`flex gap-3 mx-3 max-[899px]:flex-col max-[899px]:text-white 
      max-[899px]:gap-9 max-[767px]:w-[fit-content] max-[767px]:last:w-[70%] ${propClass}`}
    >
      {links
        .map((link) => (
          <Link
            //? Close hamburger menu
            onClick={() => setIsMenuOpen && setIsMenuOpen(false)}
            href={link.href}
            className={`w-[fit-content] hover:bg-slate-700 hover:text-primary/60 px-3 py-1 rounded-md text-sm font-medium cursor-pointer text-[1.1rem]
            ${link.admin && "bg-red-500 text-white"}
            ${
              currentPath == link.href
                ? "bg-slate-700 cursor-default shadow-1 text-primary/70 hover:text-primary/60 "
                : ""
            }`}
            key={link.label}
          >
            {link.label}
          </Link>
        ))}
    </div>
  );
};

export default NavLinks;

終わり

今回は Tailwind & Next.js でハンバーガーメニューを実装しました。
React のプロジェクトにも使用できるかと思います。

以上、お役に立てれば幸いです。


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *