Loading...
Flyoutmenu
Author Cloudapp
E.G.

Next.js 14 -Building Flyout Menu with TailwindCSS in minutes

July 20, 2024
Table of Contents

Tailwind CSS also provides utilities for interactions and transitions, enabling smooth animations. Additionally, its customization options and supportive community enhance the functionality and integration of flyout menus within a broader application ecosystem.

Here is the GitHub repo with the entire code. Below, you will find the link to the example page.

Example page hosted on Vercel -> https://nextjs14-contentful-syntax-highlighting.vercel.app/

Used Stack

I will start with my default stack:

  • Next.js 14 as the web framework, and I will use the provided middleware edge function

  • TailwindCss for Styling

  • Contentful CMS (Free Plan)

  • Vercel for hosting

We adapt the file src/components/header/navbar.component.tsx and start with some new imports.

import { Popover } from "@headlessui/react";
import { ChevronDownIcon } from "@heroicons/react/20/solid";
import {
  BookmarkSquareIcon,
  CalendarDaysIcon,
  LifebuoyIcon,
} from "@heroicons/react/24/outline";

We proceed with a new const, which is static in this example and will be replaced in a follow-up with data coming from Contentful (headless CMS).

const resources = [
    {
      name: "Overview",
      description: "Learn how to maximize our platform",
      href: "/seo-tools",
      icon: BookmarkSquareIcon,
    },
    {
      name: "Slugify",
      description: "Get all of your questions answered",
      href: "/seo-tools/slugify",
      icon: LifebuoyIcon,
    },
  ];

Now follows the integration of the menu for the desktop breakpoint (Row Number 207)

 <Popover className="relative">
                <Popover.Button className="border-transparent text-gray-500 dark:text-gray-50 hover:border-gray-300 hover:text-gray-700 inline-flex items-center text-base px-1 pt-1 border-b-2 font-medium">
                  <span>Seo-Tools</span>
                  <ChevronDownIcon className="w-5 h-5" aria-hidden="true" />
                </Popover.Button>

                <Popover.Panel className="absolute left-1/2 z-10 mt-5 flex w-screen max-w-max -translate-x-1/2 px-4 transition data-[closed]:translate-y-1 data-[closed]:opacity-0 data-[enter]:duration-200 data-[leave]:duration-150 data-[enter]:ease-out data-[leave]:ease-in">
                  <div className="flex-auto w-screen max-w-md overflow-hidden text-sm leading-6 bg-white shadow-lg rounded-3xl ring-1 ring-gray-900/5">
                    <div className="p-4">
                      {resources.map((item) => (
                        <div
                          key={item.name}
                          className="relative flex p-4 rounded-lg group gap-x-6 hover:bg-gray-50"
                        >
                          <div className="flex items-center justify-center flex-none mt-1 rounded-lg h-11 w-11 bg-gray-50 group-hover:bg-white">
                            <item.icon
                              className="w-6 h-6 text-gray-600 group-hover:text-indigo-600"
                              aria-hidden="true"
                            />
                          </div>
                          <div>
                            <a
                              href={item.href}
                              className="font-semibold text-gray-900"
                            >
                              {item.name}
                              <span className="absolute inset-0" />
                            </a>
                            <p className="mt-1 text-gray-600">
                              {item.description}
                            </p>
                          </div>
                        </div>
                      ))}
                    </div>                   
                  </div>
                </Popover.Panel>
              </Popover>

Last but not least, we integrate the menu for the mobile breakpoint (Row Number 461)

<Popover className="relative">
                <Popover.Button className="border-transparent text-gray-600 dark:text-gray-100 hover:bg-gray-100 dark:hover:text-indigo-700 hover:border-gray-300 hover:text-gray-800 block pl-3 pr-4 py-2 border-l-4 text-base font-medium">
                  <span>Seo-Tools</span>
                  <ChevronDownIcon className="w-5 h-5" aria-hidden="true" />
                </Popover.Button>

                <Popover.Panel className="absolute left-1/2 z-10 mt-5 flex w-screen max-w-max -translate-x-1/2 px-4 transition data-[closed]:translate-y-1 data-[closed]:opacity-0 data-[enter]:duration-200 data-[leave]:duration-150 data-[enter]:ease-out data-[leave]:ease-in">
                  <div className="flex-auto w-screen max-w-md overflow-hidden text-sm leading-6 bg-white shadow-lg rounded-3xl ring-1 ring-gray-900/5">
                    <div className="p-4">
                      {resources.map((item) => (
                        <div
                          key={item.name}
                          className="relative flex p-4 rounded-lg group gap-x-6 hover:bg-gray-50"
                        >
                          <div className="flex items-center justify-center flex-none mt-1 rounded-lg h-11 w-11 bg-gray-50 group-hover:bg-white">
                            <item.icon
                              className="w-6 h-6 text-gray-600 group-hover:text-indigo-600"
                              aria-hidden="true"
                            />
                          </div>
                          <div>
                            <a
                              href={item.href}
                              className="font-semibold text-gray-900"
                            >
                              {item.name}
                              <span className="absolute inset-0" />
                            </a>
                            <p className="mt-1 text-gray-600">
                              {item.description}
                            </p>
                          </div>
                        </div>
                      ))}
                    </div>                 
                  </div>
                </Popover.Panel>
              </Popover>

Final Result

It’s very easy and straightforward. In a follow-up story, we will improve it and connect the needed menu point with the Contentful CMS, so stay tuned.

Flyoutmenu example page
Flyoutmenu example page

Cloudapp-dev, and before you leave us

Thank you for reading until the end. Before you go:

Please consider clapping and following the writer! 👏 on our Medium Account

Or follow us on twitter -> Cloudapp.dev

Related articles