DEV Community

Cover image for How to create a Popover using React and Tailwind CSS
Sadekul Islam
Sadekul Islam

Posted on

How to create a Popover using React and Tailwind CSS

Popover UI elements are common in web apps, offering extra info or options when users interact with something. Usually, developers rely on npm libraries for Popovers, but these increase the project’s bundle size. In this article, I’ll guide you through building a lightweight, reusable Popover component using React and Tailwind CSS β€” with both click and hover triggers β€” so you can keep your app fast and flexible without extra dependencies.

The Popover component:

// @flow strict
"use client"
import { useEffect, useRef, useState } from "react";

function ReactPopover({
  children,
  content,
  trigger = "click"
}) {
  const [show, setShow] = useState(false);
  const wrapperRef = useRef(null);

  const handleMouseOver = () => {
    if (trigger === "hover") {
      setShow(true);
    };
  };

  const handleMouseLeft = () => {
    if (trigger === "hover") {
      setShow(false);
    };
  };

  useEffect(() => {
    function handleClickOutside(event) {
      if (wrapperRef.current && !wrapperRef.current.contains(event.target)) {
        setShow(false);
      }
    }

    if (show) {
      // Bind the event listener
      document.addEventListener("mousedown", handleClickOutside);
      return () => {
        // Unbind the event listener on clean up
        document.removeEventListener("mousedown", handleClickOutside);
      };
    }
  }, [show, wrapperRef]);

  return (
    <div
      ref={wrapperRef}
      onMouseEnter={handleMouseOver}
      onMouseLeave={handleMouseLeft}
      className="w-fit h-fit relative flex justify-center">
      <div
        onClick={() => setShow(!show)
}
      >
        {children}
      </div>
      <div
        hidden={!show}
        className="min-w-fit w-[200px] h-fit absolute bottom-[100%] z-50 transition-all">
        <div className="rounded bg-white p-3 shadow-[10px_30px_150px_rgba(46,38,92,0.25)] mb-[10px]">
          {content}
        </div>
      </div>
    </div>
  );
};

export default ReactPopover;
Enter fullscreen mode Exit fullscreen mode

In this component the trigger default value is click and you can pass hover as an attribute. When you click outside of the Popover, the Popover will be closed.

Use the Popover component:

import ReactPopover from "@/components/common/react-popover";

const Page = () => {
  return (
    <div className="w-screen h-screen flex justify-center items-center gap-4">
      <ReactPopover
        content={
          <p>This Content Will be render in Popover.</p>
        }
      >
        <button className="bg-indigo-500 px-4 py-1.5 border rounded text-white">
          Click me
        </button>
      </ReactPopover>
      <ReactPopover
        trigger="hover"
        content={
          <p>This Content Will be render in Popover.</p>
        }
      >
        <button className="bg-indigo-500 px-4 py-1.5 border rounded text-white">
          Hover me
        </button>
      </ReactPopover>
    </div>
  );
};

export default Page;
Enter fullscreen mode Exit fullscreen mode

Top comments (0)