Mapped dropdown menu won't display frontmost

Viewed 158

I just made a drop down menu for social medias in React. When I opened that drop down, it displays at back of every other component and I have a button to create another drop down menu at last of the col and when I opened another drop down above this closed drop downs, this drop downs won't stay at behind. I tried Z-index for it but it didnt't worked.

Turning input and drop down component

  let [socials, setSocials] = useState(
    props.user.data.social_medias || [
      { social_id: "Instagram" },
      { social_id: "Twitter" },
      { social_id: "Linkedin" },
    ]
  );

 <div id="web" className="w-full z-20">
    <p className="font-bold mb-4">Sosyal Medya</p>
    {
     socials.map((social,i) => (

       <Socials key={i} social={social} value={social.profile_url} />
    ))
    }
</div>

and my Socials Component

  let [socialType, setSocialType] = useState(props.social.social_id || "");
  let counter = 0;
  console.log("key" + props.key);
  let [value, setValue] = useState(props.value);
  const [showMenu, setShowMenu] = useState(false);

  const socialMedias = [
    { name: "Web Sitesi", img: web },
    { name: "LinkedIn", img: linkedIn },
    { name: "Instagram", img: instagram },
    { name: "Facebook", img: facebook },
    { name: "Twitter", img: twitter },
    { name: "Youtube", img: youtube },
  ];

  const handleChange = (e) => {
    setValue(e.target.value);
  };

  return (
    <div
      name="social-inputs"
      key={props.key}
      className="flex flex-row h-10 w-full mb-4 "
    >
      <input
        className="inline-block w-1/2 outline-none rounded px-3"
        style={{ boxShadow: "1px 1px 5px rgba(0, 49, 108, 0.2)" }}
        value={value}
        onChange={(e) => handleChange(e)}
      />
      <ul
        className="text-center ml-4 w-1/2 bg-white py-2 rounded inline-block "
        style={{ boxShadow: "1px 1px 5px rgba(0, 49, 108, 0.2)" }}
      >
        <li
          onClick={() => setShowMenu(!showMenu)}
          className={
            showMenu
              ? " px-4 flex flex-row justify-between mb-1"
              : "px-4 flex flex-row justify-between  "
          }
        >
          <p className="truncate">
            <img
              src={
                (socialMedias.find(function (element) {
                  return element.name === socialType;
                }) &&
                  socialMedias.find(function (element) {
                    return element.name === socialType;
                  }).img) ||
                web
              }
              alt={
                (socialMedias.find(function (element) {
                  return element.name === socialType;
                }) &&
                  socialMedias.find(function (element) {
                    return element.name === socialType;
                  }).name) ||
                "Web"
              }
              className="mr-3 inline-block"
            />

            {(socialMedias.find(function (element) {
              return element.name === socialType;
            }) &&
              socialMedias.find(function (element) {
                return element.name === socialType;
              }).name) ||
              "Web"}
          </p>
          <img
            src={arrow}
            alt="arrow"
            className="flex justify-end items-center "
          />
        </li>
        <Medias
          showMenu={showMenu}
          setShowMenu={setShowMenu}
          setSocialType={setSocialType}
        />
      </ul>
    </div>
  );

and for map all values in drop down component is Medias

const Medias = (props) => {
  let { showMenu } = props;
  console.log(showMenu);
  const socialMedias = [
    { name: "Web Sitesi", img: web },
    { name: "LinkedIn", img: linkedIn },
    { name: "Instagram", img: instagram },
    { name: "Facebook", img: facebook },
    { name: "Twitter", img: twitter },
    { name: "Youtube", img: youtube },
  ];
  const mappedMedias = socialMedias.map((media, i) => {
    return (
      <li
        key={i}
        onClick={() => {
          props.setSocialType(media.name);
          props.setShowMenu(false);
        }}
        style={{ boxShadow: "1px 1px 5px rgba(0, 49, 108, 0.2)" }}
        className={
          showMenu
            ? "inline-block w-full bg-white px-3 py-3 linksBlue z-50 flex items-center"
            : "hidden"
        }
      >
        <img src={media.img} alt={media.name} className="mr-3" />
        {media.name}
      </li>
    );
  });

  return (
    <div className={showMenu ? "block z-50" : "hidden"}>{mappedMedias}</div>
  );
};

and lastly my images of problem are like this. None click None click When I click only the first drop down When clicked first dropdown

When I click both first and second drop down

When I click both first and second drop down

3 Answers

From W3Schools

z-index only works on positioned elements (position: absolute, position: relative, position: fixed, or position: sticky) and flex items (elements that are direct children of display:flex elements)

Add flex class or position: relative to your <ul> element add add z-index to your <li> elements greater than <Socials> component. It is hard to determine real issue without styles.

you should take a look at parents. If a side blind of your menus parent have a greater z-index the sons of it will be on top of your menus . If your menus have a z-index of 1000 and their parent has a z-index of 1 an a side blind have a z-index of 2 its children will be on top of the menus

If you add a z-index value to your dropdown menus, but it is the same for all of them, the latest ones will always be in top of the previous ones. So, let me suggest a different approach.

Try assigning an identifier class to <li> element of Medias component (e.g. .media-option).

Then, in the onClick value at <li> element of Socials component, use a function that hides all media menus before showing the one that have been clicked. Something like this:

const onMenuClick = () => {
  const mediaOptions = document.querySelectorAll('.media-option')
  mediaOptions.map((mediaOption) => mediaOption.classList.add('hidden'))
  setShowMenu(!showMenu)
}

If that doesn't work, please share a full and working version of your code.

Related