saadeghi / daisyui

๐ŸŒผ ๐ŸŒผ ๐ŸŒผ ๐ŸŒผ ๐ŸŒผ โ€ƒThe most popular, free and open-source Tailwind CSS component library
https://daisyui.com
MIT License
34.14k stars 1.3k forks source link

bug: dropdown breaks in tables with overflow applied #3141

Open Flo0807 opened 4 months ago

Flo0807 commented 4 months ago

What version of daisyUI are you using?

v4.12.10

Which browsers are you seeing the problem on?

All browsers

Reproduction URL

https://play.tailwindcss.com/zW20wMgehO

Describe your issue

I want to place a dropdown inside a table that has a horizontal scrollbar, but it does not seem to work properly. I expect the dropdown menu to be placed above the table, but it is rendered inside the table. In the provided playground example, you can see that the second table has a vertical scrollbar and the dropdown menu is not placed properly.

If I remove the overflow-x-auto class, everything seems to work fine, but I cannot do this in my table because I want to keep a horizontal scrollbar.

github-actions[bot] commented 4 months ago

Thank you @Flo0807 for reporting issues. It helps daisyUI a lot ๐Ÿ’š
I'll be working on issues one by one. I will help with this one as soon as a I find a solution.
In the meantime providing more details and reproduction links would be helpful.

saadeghi commented 4 months ago

This is not possible by CSS until the new HTML popover API and the upcoming CSS anchor positioning API get supported by major browsers.

We're planning to add them to the next major version of daisyUI (5.x) but until then you can use JS solutions like Headless UI for the popover.

Let me know if you have a question.

moradi2128 commented 1 day ago

If you use the react framework, you can use the following code snippet It worked for me

import clsxm from "lib/clsxm";
import { useEffect, useRef, useState } from "react";

const Dropdown = () => {
  const [openUpwards, setOpenUpwards] = useState<boolean>(false);
  const dropdownRef = useRef<HTMLUListElement>(null);
  const buttonRef = useRef<HTMLDivElement>(null);
  useEffect(() => {
    if (buttonRef.current && dropdownRef.current) {
      const buttonRect = buttonRef.current.getBoundingClientRect();
      const dropdownHeight = dropdownRef.current.offsetHeight;
      const parentRect = buttonRef.current
        .closest("table") // or order of parent elements like 'div', 'span', ".content-box"
        ?.getBoundingClientRect();

      if (parentRect) {
        // Check if there's enough space to open the dropdown downwards
        const spaceBelow = parentRect.bottom - buttonRect.bottom;
        if (spaceBelow < dropdownHeight) {
          setOpenUpwards(true);
        } else {
          setOpenUpwards(false);
        }
      }
    }
  }, []);

  return (
    <div className="flex flex-col gap-1">
      <div className={clsxm("dropdown", openUpwards ? "dropdown-top" : "")}>
        <div tabIndex={0} role="button" className="relative" ref={buttonRef}>
          open
        </div>
        <ul
          tabIndex={0}
          className="mt-2 dropdown-content menu bg-base-100 rounded-box z-[1] min-w-32 p-2 shadow-dropdown"
          ref={dropdownRef}
        >
          <li>
            <a>item 1</a>
          </li>
          <li>
            <a>item 2</a>
          </li>
        </ul>
      </div>
    </div>
  );
};

export default Dropdown;