Z-Index stacking issue in React/tailwind application

Advertisements

I am having an issue with z-index stacking on an app I’m building. The code is displayed below. It is a react application using tailwind.css.

For the app I have a hamburger menu in the header that appears fullscreen as a modal when the hamburger symbol is clicked. The functionality works fine except on the Details.jsx page which has images displayed in a carousel using React Slick Slider.

When I open the hamburger modal in this page, the modal appears below just the image in the slider in stacking order with z-10. If I change the z-index to -z-10, the modal is stacked above the Slider image but the slider no longer functions. There must be something obvious I’m doing wrong but I cannot seem to figure it out.

App.jsx:

import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import ChatInput from "./components/ChatInput";
import Header from "./components/Header";
import Details from "./pages/Details";
import Home from "./pages/Home";
import Login from "./pages/Login";
import News from "./pages/News";
import Register from "./pages/Register";
import Saved from "./pages/Saved";

function App() {
  return (
    <>
      <Router>
        <section className="fixed bg-gray-100">
          <Header />
          <ChatInput />
        </section>
        <section className="pt-32">
          <Routes>
            <Route path="/" element={<Home />} />
            <Route path="/login" element={<Login />} />
            <Route path="/register" element={<Register />} />
            <Route path="/saved" element={<Saved />} />
            <Route path="/news" element={<News />} />
            <Route path="/details" element={<Details />} />
          </Routes>
        </section>
      </Router>
    </>
  );
}

export default App;

Header.jsx:

import HamburgerMenu from "./HamburgerMenu";

function Header() {
  return (
    <header className="relative h-16 w-full">
      <HamburgerMenu />
    </header>
  );
}

export default Header;

HamburgerMenu.jsx:

import { useState } from "react";
import { Link } from "react-router-dom";

const HamburgerMenu = () => {
  const [isModalOpen, setIsModalOpen] = useState(false);

  const toggleModal = () => {
    setIsModalOpen(!isModalOpen);
  };

  const stopPropagation = (e) => {
    e.stopPropagation();
  };

  return (
    <div>
      <button
        onClick={toggleModal}
        className="fixed top-4 right-4 p-2 rounded-md focus:outline-none z-50"
      >
        <span
          className={`block w-6 h-0.5 bg-black transition-transform duration-300 ${
            isModalOpen ? "opacity-0" : ""
          }`}
        ></span>
        <span
          className={`block w-6 h-0.5 bg-black mt-1.5 transition-opacity duration-300 ${
            isModalOpen ? "transform rotate-45 translate-y-0.5 bg-white" : ""
          }`}
        ></span>
        <span
          className={`block w-6 h-0.5 bg-black mt-1.5 transition-transform duration-300 ${
            isModalOpen ? "transform -rotate-45 -translate-y-1.5 bg-white" : ""
          }`}
        ></span>
      </button>
      {isModalOpen && (
        <div
          onClick={toggleModal}
          className={`fixed inset-0 bg-black bg-opacity-75 flex items-center justify-center z-40 ${
            isModalOpen
              ? "translate-y-0 opacity-100"
              : "translate-y-full opacity-0"
          }`}
        >
          <div
            onClick={stopPropagation}
            className="bg-black text-white w-full h-screen m-auto overflow-auto"
          >
            <div className="p-20 text-3xl">
              <Link to="/" className="block pb-4" onClick={toggleModal}>
                Home
              </Link>
              <Link to="/saved" className="block pb-4" onClick={toggleModal}>
                Saved
              </Link>
              <Link to="/news" className="block pb-4" onClick={toggleModal}>
                News
              </Link>
              <Link to="/login" className="block pb-4" onClick={toggleModal}>
                Login
              </Link>
              <Link to="/register" className="block pb-4" onClick={toggleModal}>
                Sign Up
              </Link>
            </div>
          </div>
        </div>
      )}
    </div>
  );
};

export default HamburgerMenu;

Details.jsx:

import { useState } from "react";
import { FaImage } from "react-icons/fa";
import Rating from "../components/Rating";
import Slider from "react-slick";
import clubs from "../clubs";

function Details() {
  const [activeDiv, setActiveDiv] = useState(0);
  const [showMoreDetails, setShowMoreDetails] = useState(false);
  const [showMoreAssessment, setShowMoreAssessment] = useState(false);

  const handleClick = (index) => {
    setActiveDiv(index);
  };
  console.log(clubs);

  let description = (
    <section aria-label="Description">
      <div className="my-2">Price: ${clubs.Prices.New} new</div>

      <div className="my-2">
        Details:{" "}
        {showMoreDetails
          ? clubs.description
          : `${clubs.description.substring(0, 250)}`}{" "}
        <span
          onClick={() => setShowMoreDetails(!showMoreDetails)}
          className="underline text-blue-500"
        >
          {showMoreDetails ? " less" : "...more"}
        </span>
      </div>
      <div className="my-2">
        Assessment:{" "}
        {showMoreAssessment
          ? clubs.assessment
          : `${clubs.assessment.substring(0, 250)}`}{" "}
        <span
          onClick={() => setShowMoreAssessment(!showMoreAssessment)}
          className="underline text-blue-500"
        >
          {showMoreAssessment ? " less" : "...more"}
        </span>
      </div>
    </section>
  );
  let reviews = (
    <section aria-label="Reviews">
      <Rating value={1.5} color={"#f8e825"} />
      <div className="text-sm">{clubs.reviews}</div>
      <Rating value={5} />
    </section>
  );
  let buyNow = (
    <section aria-label="Buy Now">
      <div className="flex flex-col">
        <button className="w-full p-2 bg-green-400 text-white my-2">
          Buy at 
        </button>
        <button className="w-full p-2 bg-green-400 text-white my-2">
          Buy at 
        </button>
      </div>
    </section>
  );

  const data = [description, reviews, buyNow];

  // Image data for the slider
  const images = [
    "/logo1.jpg",
    "/logo2.png",
    "/logo3.png",
  ];

  // Slider settings
  const sliderSettings = {
    dots: false,
    infinite: true,
    speed: 500,
    slidesToShow: 1,
    slidesToScroll: 1,
    swipeToSlide: true,
  };

  return (
    <section className="py-2 px-8">
      <div className="text-xl font-bold mb-3">Club Name</div>
      <div className="w-full h-80">
        {images.length > 0 ? (
          <Slider {...sliderSettings} className="relative z-10">
            {images.map((image, index) => (
              <div key={index}>
                <img
                  src={image}
                  alt={`Slide ${index + 1}`}
                  className="w-full h-80 object-contain"
                />
              </div>
            ))}
          </Slider>
        ) : (
          <div className="flex justify-center items-center bg-gray-300 w-full h-80">
            <FaImage size={80} />
          </div>
        )}
      </div>
      
      //*** Rest of code ***//

    </section>
  );
}

export default Details;

>Solution :

Consider having the fixed <section> element in App.jsx that wraps the <Header> be stacked above the <Slider> by applying a z-index value higher than 10. For example, try adding the z-50 class to it:

<Router>
  <section className="fixed bg-gray-100 z-50">
    <Header />

Leave a ReplyCancel reply