By using this site, you agree to the Privacy Policy and Terms of Use.
Accept
rocoderesrocoderes
  • Home
  • HTML & CSS
    • Login and Registration Form
    • Card Design
    • Loader
  • JavaScript
  • Python
  • Internet
  • Landing Pages
  • Tools
    • Google Drive Direct Download Link Generator
    • Word Count
  • Games
    • House Painter
Notification Show More
Latest News
How to set the dropdown value by clicking on a table row
Javascript – How to set the dropdown value by clicking on a table row
JavaScript
Attempting to increase the counter, when the object's tag exist
Javascript – Attempting to increase the counter, when the object’s tag exist
JavaScript
Cycle2 JS center active slide
Javascript – Cycle2 JS center active slide
JavaScript
Can import all THREE.js post processing modules as ES6 modules except OutputPass
Javascript – Can import all THREE.js post processing modules as ES6 modules except OutputPass
JavaScript
How to return closest match for an array in Google Sheets Appscript
Javascript – How to return closest match for an array in Google Sheets Appscript
JavaScript
Aa
Aa
rocoderesrocoderes
Search
  • Home
  • HTML & CSS
    • Login and Registration Form
    • Card Design
    • Loader
  • JavaScript
  • Python
  • Internet
  • Landing Pages
  • Tools
    • Google Drive Direct Download Link Generator
    • Word Count
  • Games
    • House Painter
Follow US
High Quality Design Resources for Free.
rocoderes > JavaScript > Javascript – How to create a slide menu with React and Headless UI (Tailwind)
JavaScript

Javascript – How to create a slide menu with React and Headless UI (Tailwind)

Admin
Last updated: 2023/12/26 at 3:47 PM
Admin
Share
7 Min Read
How to create a slide menu with React and Headless UI (Tailwind)

Problem:

I am trying to create a slide-over navbar or slide menu with panels that open on top of eachother (I haven’t found the best description yet as how to describe it).

Contents
Problem:Solution:

Basically the idea is to have a slide menu that has sub-menu items that slide in (on top of eachother) as well.
When a sub-menu item has been opened have the ‘Back’ button to go back to the main menu.

Here’s a link with full code example:
https://codesandbox.io/p/sandbox/over-lay-menu-n92xys

If you take a look at my SlidePanel.js you can see how I am trying to pass props to SlidePanelLayer.js hoping this would achieve that but in practice it does not work well:

"use client";

import { Fragment, useState } from "react";
import { Dialog, Transition } from "@headlessui/react";
import { XMarkIcon } from "@heroicons/react/24/outline";
import { MagnifyingGlassIcon } from "@heroicons/react/20/solid";
import { menuItems } from "../data/menu";

import SlidePanelLayer from "./SlidePanelLayer";

export default function SlidePanel({ slideOpen, setSlideOpen }) {
  const [openLayer, setOpenLayer] = useState(false);

  return (
    <>
      <SlidePanelLayer
        openLayer={openLayer}
        setOpenLayer={setOpenLayer}
        setSlideOpen={setSlideOpen}
      />
      <Transition.Root show={slideOpen} as={Fragment}>
        <Dialog as="div" className="relative z-50" onClose={setSlideOpen}>
          <Transition.Child
            as={Fragment}
            enter="ease-in-out duration-500"
            enterFrom="opacity-0"
            enterTo="opacity-100"
            leave="ease-in-out duration-500"
            leaveFrom="opacity-100"
            leaveTo="opacity-0"
          >
            <div className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" />
          </Transition.Child>

          <div className="fixed inset-0 overflow-hidden">
            <div className="absolute inset-0 overflow-hidden">
              <div className="pointer-events-none fixed inset-y-0 right-0 flex max-w-full pl-10">
                <Transition.Child
                  as={Fragment}
                  enter="transform transition ease-in-out duration-500 sm:duration-700"
                  enterFrom="translate-x-full"
                  enterTo="translate-x-0"
                  leave="transform transition ease-in-out duration-500 sm:duration-700"
                  leaveFrom="translate-x-0"
                  leaveTo="translate-x-full"
                >
                  <Dialog.Panel className="pointer-events-auto w-screen max-w-md">
                    <div className="flex h-full flex-col overflow-y-scroll bg-white py-6 shadow-xl rounded-l-2xl">
                      <div className="px-4 sm:px-6">
                        <div className="flex items-start justify-between">
                          <div className="flex h-7 items-center">
                            <button
                              type="button"
                              className="flex gap-2 items-center relative rounded-md bg-white text-gray-400 hover:text-gray-500"
                              onClick={() => setSlideOpen(false)}
                            >
                              <span className="sr-only">Close</span>
                              <XMarkIcon
                                className="h-5 w-5 text-secondary-90"
                                aria-hidden="true"
                              />
                              <span className="text-gray-900 font-bold">
                                Close
                              </span>
                            </button>
                          </div>
                        </div>
                      </div>
                      <div className="relative mt-6 flex-1 px-4 sm:px-6">
                        {/* Start content */}

                        <div className="mt-6 flow-root">
                          <div className="-my-6">
                            <div className="space-y-2 pt-6 pb-4">
                              {menuItems.map((item) => (
                                <a
                                  key={item.title}
                                  href={item.href}
                                  onClick={() => setOpenLayer(true)}
                                  className="-mx-3 block rounded-lg px-3 py-2 text-base leading-7 text-secondary-90 hover:bg-gray-50 font-bold"
                                >
                                  {item.title}
                                </a>
                              ))}
                            </div>
                          </div>
                        </div>

                        {/* End content */}
                      </div>
                    </div>
                  </Dialog.Panel>
                </Transition.Child>
              </div>
            </div>
          </div>
        </Dialog>
      </Transition.Root>
    </>
  );
}

Solution:

Header.js:

"use client";

import { useState } from "react";

import { Bars3Icon } from "@heroicons/react/24/outline";

import SlidePanel from "@/components/SlidePanel";

export default function HeaderComponent() {
  const [activeNavbar, setActiveNavbar] = useState("");
  return (
    <header className="relative isolate z-40">
      <div className="flex lg:flex-1 justify-between items-center  mx-auto max-w-7xl px-6 lg:px-8 py-4 lg:py-8">
        <a href="/" className="-m-1.5 p-1.5">
          <span className="sr-only">Over-lay</span>
          <span>Over-lay menu</span>
        </a>

        <div className="flex">
          <button
            type="button"
            className="-m-2.5 inline-flex items-center justify-center rounded-md p-2.5 text-gray-700"
            onClick={() => setActiveNavbar("mainMenu")}
          >
            <span className="sr-only">Open menu</span>
            <Bars3Icon className="h-6 w-6" aria-hidden="true" />
          </button>
        </div>
      </div>

      <SlidePanel
        activeNavbar={activeNavbar}
        setActiveNavbar={setActiveNavbar}
      />
    </header>
  );
}

SlidePannel.js:

"use client";

import { Fragment, useState } from "react";
import { Dialog, Transition } from "@headlessui/react";
import { XMarkIcon } from "@heroicons/react/24/outline";
import { MagnifyingGlassIcon } from "@heroicons/react/20/solid";
import { menuItems } from "../data/menu";

import SlidePanelLayer from "./SlidePanelLayer";

export default function SlidePanel({ activeNavbar, setActiveNavbar }) {
  // const [openLayer, setOpenLayer] = useState(false);
  return (
    <>
      <SlidePanelLayer
        activeNavbar={activeNavbar}
        setActiveNavbar={setActiveNavbar}
      />
      <Transition.Root show={!!activeNavbar} as={Fragment}>
        <Dialog
          as="div"
          className="relative z-50"
          onClose={() => setActiveNavbar("")}
        >
          <Transition.Child
            as={Fragment}
            enter="ease-in-out duration-500"
            enterFrom="opacity-0"
            enterTo="opacity-100"
            leave="ease-in-out duration-500"
            leaveFrom="opacity-100"
            leaveTo="opacity-0"
          >
            <div className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" />
          </Transition.Child>

          <div className="fixed inset-0 overflow-hidden">
            <div className="absolute inset-0 overflow-hidden">
              <div className="pointer-events-none fixed inset-y-0 right-0 flex max-w-full pl-10">
                <Transition.Child
                  as={Fragment}
                  enter="transform transition ease-in-out duration-500 sm:duration-700"
                  enterFrom="translate-x-full"
                  enterTo="translate-x-0"
                  leave="transform transition ease-in-out duration-500 sm:duration-700"
                  leaveFrom="translate-x-0"
                  leaveTo="translate-x-full"
                >
                  <Dialog.Panel className="pointer-events-auto w-screen max-w-md">
                    <div className="flex h-full flex-col overflow-y-scroll bg-white py-6 shadow-xl rounded-l-2xl">
                      <div className="px-4 sm:px-6">
                        <div className="flex items-start justify-between">
                          <div className="flex h-7 items-center">
                            <button
                              type="button"
                              className="flex gap-2 items-center relative rounded-md bg-white text-gray-400 hover:text-gray-500"
                              onClick={() => setActiveNavbar("")}
                            >
                              <span className="sr-only">Close</span>
                              <XMarkIcon
                                className="h-5 w-5 text-secondary-90"
                                aria-hidden="true"
                              />
                              <span className="text-gray-900 font-bold">
                                Close
                              </span>
                            </button>
                          </div>
                        </div>
                      </div>
                      <div className="relative mt-6 flex-1 px-4 sm:px-6">
                        {/* Start content */}

                        <div className="mt-6 flow-root">
                          <div className="-my-6">
                            <div className="space-y-2 pt-6 pb-4">
                              {menuItems.map((item) => (
                                <a
                                  key={item.title}
                                  href={item.href}
                                  onClick={() => setActiveNavbar(item.title)}
                                  className="-mx-3 block rounded-lg px-3 py-2 text-base leading-7 text-secondary-90 hover:bg-gray-50 font-bold"
                                >
                                  {item.title}
                                </a>
                              ))}
                            </div>
                          </div>
                        </div>

                        {/* End content */}
                      </div>
                    </div>
                  </Dialog.Panel>
                </Transition.Child>
              </div>
            </div>
          </div>
        </Dialog>
      </Transition.Root>
    </>
  );
}

SlidePannelLayer.js:

import { Fragment, useState } from "react";
import { Dialog, Transition } from "@headlessui/react";
import { ChevronLeftIcon } from "@heroicons/react/20/solid";

import { about } from "../data/menu";

export default function SlidePanelLayer({ activeNavbar, setActiveNavbar }) {
  //  const [open, setOpen] = useState(true);
  return (
    <Transition.Root
      show={!!activeNavbar && activeNavbar !== "mainMenu"}
      as={Fragment}
    >
      <Dialog
        as="div"
        className="relative z-50"
        onClose={() => {
          setActiveNavbar("mainMenu");
        }}
      >
        {/* <Transition.Child
          as={Fragment}
          enter="ease-in-out duration-500"
          enterFrom="opacity-0"
          enterTo="opacity-100"
          leave="ease-in-out duration-500"
          leaveFrom="opacity-100"
          leaveTo="opacity-0"
        >
          <div className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" />
        </Transition.Child> */}

        <div className="fixed inset-0 overflow-hidden">
          <div className="absolute inset-0 overflow-hidden">
            <div className="pointer-events-none fixed inset-y-0 right-0 flex max-w-full pl-10">
              <Transition.Child
                as={Fragment}
                enter="transform transition ease-in-out duration-500 sm:duration-700"
                enterFrom="translate-x-full"
                enterTo="translate-x-0"
                leave="transform transition ease-in-out duration-500 sm:duration-700"
                leaveFrom="translate-x-0"
                leaveTo="translate-x-full"
              >
                <Dialog.Panel className="pointer-events-auto w-screen max-w-md">
                  <div className="flex h-full flex-col overflow-y-scroll bg-white py-6 shadow-xl rounded-l-2xl">
                    <div className="px-4 sm:px-6">
                      <div className="flex items-start justify-between">
                        <div className="flex h-7 items-center">
                          <button
                            type="button"
                            className="flex gap-2 items-center relative rounded-md bg-white text-gray-400 hover:text-gray-500"
                            onClick={() => setActiveNavbar("mainMenu")}
                          >
                            <span className="sr-only">Back</span>
                            <ChevronLeftIcon
                              className="h-5 w-5 text-secondary-90"
                              aria-hidden="true"
                            />
                            <span className="text-gray-900 font-bold">
                              Back
                            </span>
                          </button>
                        </div>
                      </div>
                      <div className="text-secondary-90 font-bold mt-6">
                        About
                      </div>
                      <hr className="my-6" />
                    </div>
                    <div className="relative flex-1 px-4 sm:px-6">
                      {about.map((item) => (
                        <div
                          key={item.title}
                          className="relative pb-12 leading-6"
                        >
                          <h2 className="mt-1 text-secondary-90 text-2xl font-bold">
                            {item.title}
                          </h2>
                          <p className="mt-1 mb-6 text-secondary-90">
                            {item.description}
                          </p>
                          {item.links.map((link) => (
                            <a
                              key={link.title}
                              href={link.href}
                              className="mt-4 block text-secondary-90 hover:text-secondary-100 group"
                            >
                              <span className="flex items-center">
                                {link.icon && (
                                  <link.icon
                                    className="flex-none w-5 h-5 text-gray-400"
                                    aria-hidden="true"
                                  />
                                )}
                                <span className="ml-2 font-bold group-hover:underline">
                                  {link.title}
                                </span>
                              </span>
                              <span className="block text-sm">
                                {link.description}
                              </span>
                            </a>
                          ))}
                        </div>
                      ))}
                    </div>
                  </div>
                </Dialog.Panel>
              </Transition.Child>
            </div>
          </div>
        </div>
      </Dialog>
    </Transition.Root>
  );
}

Related

Subscribe to Our Newsletter

Subscribe to our newsletter to get our newest articles instantly!

Share this Article
Facebook Twitter Email Print
What do you think?
Love0
Sad0
Happy0
Sleepy0
Angry0
Dead0
Wink0
Previous Article Blazor: Removing an element from c# code works only once, then resets the connection Javascript – Blazor: Removing an element from c# code works only once, then resets the connection
Next Article Property 'includes' does not exist on type 'RouteRecordName' Javascript – Property ‘includes’ does not exist on type ‘RouteRecordName’
Leave a comment Leave a comment

Leave a Reply Cancel reply

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

- Advertisement -

You Might Also Like

How to set the dropdown value by clicking on a table row

Javascript – How to set the dropdown value by clicking on a table row

February 11, 2024
Attempting to increase the counter, when the object's tag exist

Javascript – Attempting to increase the counter, when the object’s tag exist

February 11, 2024
Cycle2 JS center active slide

Javascript – Cycle2 JS center active slide

February 10, 2024
Can import all THREE.js post processing modules as ES6 modules except OutputPass

Javascript – Can import all THREE.js post processing modules as ES6 modules except OutputPass

February 10, 2024
rocoderesrocoderes
Follow US

Copyright © 2022 All Right Reserved By Rocoderes

  • Home
  • About us
  • Contact us
  • Disclaimer
Join Us!

Subscribe to our newsletter and never miss our latest news, podcasts etc.

Zero spam, Unsubscribe at any time.
Welcome Back!

Sign in to your account

Lost your password?