concealing the dropdown in React upon clicking outside of it

I have been delving into learning React by challenging myself with a React problem. The code challenge I'm facing involves trying to close a drop-down when clicking outside of it. Despite my efforts to debug, I haven't had much luck in solving this issue.

Can anyone provide insights or comments on the code toolbar? Understanding the video explaining each functionality has proven difficult for me. Additionally, I've looked up information on spread and useRef but am unsure why spread is being used in this particular instance.

After further searching without success, I am feeling stuck on how to resolve this problem. Below is the code I have written along with a StackBlitz link. Any assistance you can offer would be greatly appreciated.

YouTube Video

StackBlitz Code

import { useEffect, useRef, useState } from 'react';
import './stateDropdown.css';
import { states } from './States';
export function StateDropdown() {
  const [isDropDownDisplayed, setIsDropdowndisplayed] = useState(false);
  const [selectedStates, setSelectedStates] = useState<Record<string, boolean>>(
    states.reduce((obj, state) => ({ ...obj, [state.abbreviation]: false }), {})
  );
  const numberOfStatesSelected =
    Object.values(selectedStates).filter(Boolean).length;
  const dropDownRef = useRef(null);
  useEffect(() => {
    const onClick = (e: any) => {
      if (e.target !== dropDownRef.current) {
        console.log('we are here');
        setIsDropdowndisplayed(false);
      }
    };
    document.addEventListener('click', () => {});
    // clean up
    return () => {
      document.removeEventListener('click', onClick);
    };
  }, []);
  return (
    <fieldset className="state-dropdown">
      <button
        className=""
        onClick={(e) => {
          e.stopPropagation();
          setIsDropdowndisplayed((prevState) => !prevState);
        }}
      >
        {numberOfStatesSelected > 0
          ? `${numberOfStatesSelected} states selected`
          : '-- Select your states --'}

        <svg
          xmlns="http://www.w3.org/2000/svg"
          fill="none"
          viewBox="0 0 24 24"
          stroke-width="1.5"
          stroke="currentColor"
          className="w-6 h-6"
        >
          <path
            stroke-linecap="round"
            stroke-linejoin="round"
            d="M6 13.5V3.75m0 9.75a1.5 1.5 0 010 3m0-3a1.5 1.5 0 000 3m0 3.75V16.5m12-3V3.75m0 9.75a1.5 1.5 0 010 3m0-3a1.5 1.5 0 000 3m0 3.75V16.5m-6-9V3.75m0 3.75a1.5 1.5 0 010 3m0-3a1.5 1.5 0 000 3m0 9.75V10.5"
          />
        </svg>
      </button>
      {isDropDownDisplayed && (
        <div
          onClick={(e) => {
            e.stopPropagation();
          }}
          ref={dropDownRef}
          className="panel"
        >
          {states.map((state) => (
            <fieldset
              key={state.abbreviation}
              className={selectedStates[state.abbreviation] ? `selected` : ''}
            >
              <input
                onChange={(e) =>
                  setSelectedStates({
                    ...selectedStates,
                    [state.abbreviation]: e.target.checked,
                  })
                }
                checked={selectedStates[state.abbreviation]}
                id={`input-${state.abbreviation}`}
                type="checkbox"
              />
              <label htmlFor={`input-${state.abbreviation}`}>
                {state.name}
              </label>
            </fieldset>
          ))}
        </div>
      )}
    </fieldset>
  );
}

Answer №1

If you want the menu to close when clicking outside of it, all you need to do is update the following code:

document.addEventListener('click', () => {});

Change it to:

document.addEventListener('click', onClick);

Currently, you are adding an event listener without any functionality, but by using onClick function, you can check if the click occurred within the menu or not.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Choose a navigation item from the list containing a nested span element

I've implemented selectnav from GitHub and it's functioning perfectly. However, my menu consists of list items with a description span inside each one, resulting in menu items structured as shown below: <li><a href="somelink.html">Ch ...

I encountered a sudden halt in functionality with my NextJs useState feature

'use client' import React, { useState } from 'react'; import Image from 'next/image'; export default function Home() { const [count,setCount] = useState<number>(0) const add = ()=> { setCount(prevCount => ...

How can I transfer data from two queries to Jade using Node.js (Express.js)?

I have a database with two tables - one for storing user information and another for managing friendship connections: setting up a friend list in mysql My goal is to create a profile page using Jade, specifically profile.jade: - each user in users ...

Best practices for locating unique symbols within a string and organizing them into an array using JavaScript

Here is an example string: "/city=<A>/state=<B>/sub_div=<C>/type=pos/div=<D>/cli_name=Cstate<E>/<F>/<G>" The characters A, B, C, and so on are variables, and their count is not fixed. Can you determine how many ...

The class "Accordion" is not recognized by the local Bootstrap 5 installation

Currently, I am trying to implement a vertically collapsing Accordion using the Bootstrap 5 documentation found at https://getbootstrap.com/docs/5.0/components/accordion/ Even though I have installed the library with libman, Visual Studio 2019 is showing ...

How can you ensure that divs stay the same size and appear next to each other without resorting to using

I need assistance with organizing my website layout as shown below: https://i.sstatic.net/Dpof9.png The image div will display an image of variable size, which needs to be vertically and horizontally centered. The text div will contain a large amount of ...

ways to make a list element inaccessible by using either Javascript or jQuery

When the user clicks on my eraser, I want the color to be hidden or not display its dropdown elements. I attempted this with the following code snippet. $('#chooseEraser').mousedown(function(e){ curTool = "eraser"; checkEraser ...

What is the method for showing multiple lines in the X-Axis tick labels in Recharts?

When it comes to charting libraries, I find this one to be the most effective for my needs, except for one issue – handling long string values as X axis tick labels. I attempted various solutions like creating a separate div or using a map to align the ...

How can you make sure that mouse events pass through the KineticJS stage?

Is it possible to have a PanoJS3 component covering the entire screen with a KineticJS stage on top, but still allow touch events to pass through the KineticJS stage to what lies beneath? I want shapes on the stage or layer to receive the touch events, wh ...

Tips for managing blur events to execute personalized logic within Formik

I am currently delving into the world of React/Next.js, Formik, and Yup. My goal is to make an API call to the database upon blurring out of an input field. This call will fetch some data, perform database-level validation, and populate the next input fiel ...

What is the best way to transfer the window object from the current tab to the extension?

I am looking to retrieve user storage data (local and session) from a specific tab, similar to what is shown in this app (see screen below). From my understanding, I need to access the window object of the active tab. While I have obtained the object, I a ...

Ways to Halt Every Single CSS Animation

Is there a way to stop all CSS animations in a document from the beginning? My idea is to assign a class to elements containing CSS animations at the start, such as '.paused'. Then, using jQuery in my JavaScript, I would remove the '.paused& ...

What's the best way to refresh append() functionality within a modal? I'm currently working with NODE JS and AJAX and

Whenever I click the modal, the append() calls are adding HTML content. But if I try to use empty() or html(), the modal stops appearing altogether. What is the correct approach to creating this modal? function loadModalContent(id) { $('#myModal& ...

"Choosing the text within an <a> tag: A step-by

I am dealing with the a tag. <a href="mailto:<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="b4c7dbd9d1f4d9d5ddd89ad7dbd9">[email protected]</a>"><a href="/cdn-cgi/l/email-protection" class="__cf_email__" ...

Sending the method's URL in the controller through an AJAX call

Below is the code snippet for an ajax call: <script> jQuery(document).ready(function() { $("#VEGAS").submit(function(){ var form_data = $("#VEGAS").serialize(); var routeUrl = "<?= url('/'); ?> /PUBLIC/vpage"; $.ajax({ ...

Unusual occurrence in Chrome when checking definitions: ReferenceError: x is not defined

Recently, I've come across some odd behavior in Chrome following its latest update. Whenever I try to determine if a variable is defined, it ends up triggering an uncaught error like the one shown below: if(x) { alert('x is defined.'); } T ...

Update the content of the document element by assigning it a lengthy string

I'm utilizing JQuery to dynamically assign content to a div element. The content has numerous lines with specific spacing, so this is the approach I am taking: document.getElementById('body').innerHTML = "Front-End Developer: A <br/> ...

Select box in material design does not show an error when the value is empty

<md-input-container flex-gt-xs> <label translate>rule.type.title</label> <md-select name="type" ng-required="true" ng-model="vm.model.type" ng-change="vm.onRuleTypeChange(vm.model.type)"> <md-op ...

Determine the currently active view on a mobile device

I am trying to determine whether the user is viewing the website vertically or horizontally on their mobile device or iPad in order to adjust the image scale accordingly. For example: If the user is viewing the page horizontally, I want the image style t ...

Error message: The provider is not being recognized by react-redux while using NextJS with RTK and

Struggling to integrate Redux RTK into my Next JS 13.4 app has been quite the challenge. No matter how many tutorials I follow, I keep encountering the same error in my provider.ts file. 'use client' import { store } from './store'; imp ...