skip to Main Content

I’m working on my navbar. I have a header with a component within called HeaderSearch. What I want is to run a function each time the user clicks outside of the HeaderSearch. And then add an animation to close it.

Here is my HeaderSearch:

//searchBar component
  const HeaderSearch = () => {
    if (location.pathname !== "/") {
      return (
        <div id="search-header" className="search-header">
          <FontAwesomeIcon
            className="search-icon"
            id="search-icon"
            icon={faSearch}
            // onClick={() => searchReqClientSide()}
            onClick={() => searchOpen()}
          />
          <input
            id="search-input"
            type="text"
            value={search}
            onKeyDown={(e) => checkInput(e)}
          />
        </div>
      );
    } else {
      return null;
    }
  };

Here is my onClickOutside function which is a modification of this function

// detect click and then determine whether isclicked inside searchInput or outside
  const onClickOutside = () => {
    console.log("first");
    const searchInput = document.getElementById("search-input");
    if (searchInput.classList.contains("active")) {
      console.log("second,  contains active true");
      document.addEventListener("click", (e) => {
        console.log("third,  beginning click");
        if (!searchInput.contains(e.target)) {
          console.log("fourth, searchInput does not contain clicked element");
          searchInput.classList.remove("active");
          setTimeout(() => {
            searchInput.style.animation = "searchInputClose 0.5s ease";
            console.log("fifth, during timeout");
          }, 500);
        }
      });
    }
    console.log("sixth, after everything");

  };

And here is my searchOpen function :

const searchOpen = () => {
    const searchInput = document.getElementById("search-input");
    const searchHeader = document.getElementById("search-header");
    const searchIcon = document.getElementById("search-icon");
    if (!searchInput.classList.contains("active")) {
      searchInput.style.animation = "searchInputOpen 0.5s ease";
      setTimeout(() => {
        searchInput.classList.add("active");
      }, 500);
    }
  };

Where do I excecute the onClickOutside function. I tried putting it in useEffect(() => { onClickOutside })
and useEffect(() => { onClickOutside },[])

Thank you

2

Answers


  1. You should add the function you want to execute in the parent element which contains HeaderSearch eg: <div onClick={onClickOutside}> <HeaderSearch/> </div>.

    Login or Signup to reply.
  2. To detect clicks outside of the HeaderSearch component and close it with an animation, you should add the onClickOutside event listener in a useEffect hook when the component mounts, and remove it when the component unmounts to avoid memory leaks.

    This is my demo code.

    import { useEffect, useRef, useState } from "react";
    import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
    import { faSearch } from "@fortawesome/free-solid-svg-icons";
    
    const HeaderSearch = () => {
        const [search, setSearch] = useState("");
        const searchInputRef = useRef<any>(null);
        const searchHeaderRef = useRef<any>(null);
    
        useEffect(() => {
          document.addEventListener("click", handleClickOutside);
          return () => {
            document.removeEventListener("click", handleClickOutside);
          };
        }, []);
      
        const searchOpen = () => {
          const searchInput = searchInputRef.current;
          if (searchInput && !searchInput.classList.contains("active")) {
            searchInput.style.animation = "searchInputOpen 0.5s ease";
            setTimeout(() => {
              searchInput.classList.add("active");
            }, 500);
          }
        };
      
        const searchClose = () => {
          const searchInput = searchInputRef.current;
          if (searchInput.classList.contains("active")) {
            searchInput.style.animation = "searchInputClose 0.5s ease";
            setTimeout(() => {
              searchInput.classList.remove("active");
            }, 500);
          }
        };
      
        const handleClickOutside = (e: any) => {
          if (
            searchHeaderRef.current &&
            !searchHeaderRef.current.contains(e.target)
          ) {
            searchClose();
          }
        };
      
        const checkInput = (e: any) => {
          if (e.key === "Enter") {
            console.log("Search value: ", search);
          }
        };
      
        return (
          <div id="search-header" className="search-header" ref={searchHeaderRef}>
            <FontAwesomeIcon
              className="search-icon"
              id="search-icon"
              icon={faSearch}
              onClick={searchOpen}
            />
            <input
              id="search-input"
              type="text"
              value={search}
              onChange={(e) => setSearch(e.target.value)}
              onKeyDown={checkInput}
              ref={searchInputRef}
              placeholder="Search..."
            />
          </div>
        );
    };
      
    export default HeaderSearch;
    

    Feel free to personalize this code. I hope this will solve your issue.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search