how to target just one dropdown menu instead of all?

I have a react project where I have 3 dropdown menus side by side and upon clicking one they all will toggle instead of just one. I tried to use a dropdown component but I’m not sure I can get it working correctly with my code. Can you show me how to fix this? I have my code uploaded to code sandbox here link to code due note that it will not display on mobile screens yet so you will need to look at it in the full desktop version of the site.

import { useState } from 'react';
import {
  iconHamburger,
  iconClose,
  iconArrowDark,
  iconArrowLight,
  logo,
} from '../assets';
import { navLinks } from '../constants';

const Navbar = () => {
  const [toggle, setToggle] = useState(false);

  return (
    <nav className='w-full flex py-6 ml-10 justify-between items-center navbar'>
      <img src={logo} alt='blogr' className='w-[75px] h-[30px]' />

      <ul className='list-none sm:flex hidden ml-10 justify-start items-center flex-1'>

        {navLinks.map((nav, index) => (
          <li
            key={nav.id}
            className={`font-overpass
            font-normal
            text-[12px] ${index === navLinks.length - 1 ? 'mr-0' : 'mr-10'}
          text-white`}>
            <a
              className='float-left'
              onClick={() => setToggle((prev) => !prev)}
              href={`#${nav.id}`}>
              {nav.title}
              <img
                className='ml-2 mt-1 cursor-pointer float-right w-[9px] h-[6px]'
                src={iconArrowLight}
              />
            </a>

            <div className={`${toggle ? 'hidden' : 'relative'} mr-10`}>
              <ul className='list-none mt-10 absolute'>
                {nav.links.map((link, index) => (
                  <li
                    key={link.name}
                    className={`font-overpass text-black cursor-pointer ${
                      index !== nav.links.length - 1 ? 'mb-4' : 'mb-0'}`}>
                    {link.name}
                  </li>
                ))}
              </ul>
            </div>
          </li>              
          

        ))}
      </ul>

      
    </nav>
  );
};

export default Navbar;

navlinks

import { iconArrowLight } from "../assets"

export const navLinks = [
    {
        id: 'product',
        title: 'Product',
        img: iconArrowLight,
        links: [
            {
                name: 'Overview'
            },
            {
                name: 'Pricing'
            },
            {
                name: 'Marketplace'
            },
            {
                name: 'Features'
            },
            {
                name: 'Integrations'
            },
        ],
    },
    {   
        id: 'company',
        title: 'Company',
        img: iconArrowLight,
        links: [
            {
                name: 'About'
            },
            {
                name: 'Team'
            },
            {
                name: 'Blog'
            },
            {
                name: 'Career'
            },
        ],
    },
    {
        id: 'connect',
        title: 'Connect',
        img: iconArrowLight,
        links: [
            {
                name: 'Contact'
            },
            {
                name: 'Newsletter'
            },
            {
                name: 'LinkedIn'
            },
        ],
    },
]

>Solution :

All the drop list is sharing one toggle state, therefore they open and close at same time.

You could make each drop list a separate component DropList, each will have an individual state of toggle.

It will allow adding more DropList easier, also keeping the code in Navbar cleaner.

Full example: (live modified project: codesandbox)

import { useState } from "react";
import {
  iconHamburger,
  iconClose,
  iconArrowDark,
  iconArrowLight,
  logo,
} from "../assets";
import { navLinks } from "../constants";

const Navbar = () => {
  return (
    <nav className="w-full flex py-6 ml-10 justify-between items-center navbar">
      <img src={logo} alt="blogr" className="w-[75px] h-[30px]" />

      <ul className="list-none sm:flex hidden ml-10 justify-start items-center flex-1">
        {navLinks.map((nav, index, arr) => (
          <DropList
            key={nav.id}
            mr={index === arr.length - 1 ? "mr-0" : "mr-10"}
            {...nav}
          />
        ))}
      </ul>
    </nav>
  );
};

export default Navbar;

export const DropList = ({ id, title, links, mr }) => {
  const [toggle, setToggle] = useState(false);

  return (
    <li
      className={`font-overpass
            font-normal
            text-[12px] ${mr}
          text-white`}
    >
      <a
        className="float-left"
        onClick={() => setToggle((prev) => !prev)}
        href={`#${id}`}
      >
        {title}
        <img
          className="ml-2 mt-1 cursor-pointer float-right w-[9px] h-[6px]"
          src={iconArrowLight}
        />
      </a>

      <div className={`${toggle ? "hidden" : "relative"} mr-10`}>
        <ul className="list-none mt-10 absolute">
          {links.map((link, index, arr) => (
            <li
              key={link.name}
              className={`font-overpass text-black  ${
                index !== arr.length - 1 ? "mb-4" : "mb-0"
              }`}
            >
              {link.name}
            </li>
          ))}
        </ul>
      </div>
    </li>
  );
};

Leave a Reply