How can I prevent the antd dropdown menu from closing when clicking on it?

I am currently working on integrating an Antd Dropdown Menu with Search functionality. My goal is to have the dropdown close when clicking outside of it. However, in my code, the dropdown toggles between opening and closing even if I click on the Search box (which is not the desired behavior). I want the dropdown menu to only be open if there is text input in the search box, and to close if there is no text or if clicked outside. It should not continuously open and close when I click on the search box itself. Is there a specific property that I might be overlooking? Here is a snippet of the code:

import React from "react";
import ReactDOM from "react-dom";
import "antd/dist/antd.css";
import "./index.css";
import { Menu, Dropdown, Input } from "antd";

class OverlayVisible extends React.Component {
  state = {
    visible: false
  };

  handleMenuClick = (e) => {
    if (e.key === "3") {
      this.setState({ visible: false });
    }
  };

  handleVisibleChange = (flag) => {
    this.setState({ visible: flag });
  };

  render() {
    const menu = (
      <Menu onClick={this.handleMenuClick}>
        <Menu.Item key="1">Clicking me will not close the menu.</Menu.Item>
      </Menu>
    );
    return (
      <Dropdown
        onClick={() => {
          this.setState({ visible: true });
        }}
        overlay={menu}
        onVisibleChange={this.handleVisibleChange}
        visible={this.state.visible}
        trigger={["click"]}
      >
        <Input.Search
          onInput={() => {
            this.setState({ visible: true });
          }}
        ></Input.Search>
        
      </Dropdown>
    );
  }
}

ReactDOM.render(<OverlayVisible />, document.getElementById("container"));

CodeSandbox Link: https://codesandbox.io/s/aman-521r2?file=/index.js:0-1236

Answer №1

Encountered a similar problem and resolved it by including

onClick={(e) => e?.stopPropagation()}
in the element that should prevent closing the overlay when clicked

Answer №2

For AntDesign version 5+

To maintain the dropdown open even when a menu item is clicked, you can use a boolean state and handle specific events. In this example, I demonstrate how to keep the dropdown open for certain menu item keys while allowing it to close for others. For instance, only the menu item with the key menuItemKeyWhichShouldNotClose will not close the dropdown upon selection.

      <Dropdown
        open={open}
        menu={{
          items,
          onClick: (info: MenuInfo): void => {
            if (info.key !== menuItemKeyWhichShouldNotClose) setOpen(false)
          },
          onMouseLeave: (): void => setOpen(false),
        }}
      >
        <Button onMouseEnter={(): void => setOpen(true)}>
          <AiOutlineEllipsis />
        </Button>
      </Dropdown>

Answer №3

To achieve this, consider making a modification to the Input Search feature.

<Input.Search
          onChange={(e) => {
         
            if (e.target.value.length) {

              this.setState({ visible: true });
              return false;
            }
            this.setState({ visible: false });
          }}
        ></Input.Search>

Additionally, delete the usage of setstate from the function handleVisibleChange

  handleVisibleChange = (flag) => {
 
  };

Answer №4

If you are looking to resolve the problem, one solution is to add the attribute disabled to the Item element in this manner:

<Menu.Item key="1" disabled>Clicking me will not close the menu.</Menu.Item>

Answer №5

Ensure to include an additional state for storing input values.

 state = {
    visible: false,
    value: ''
  };

Assign the input value to the state when the user types the value in the input field

<Input.Search
   onInput={() => {
     this.setState({ visible: true });
   }}
   onChange={e => this.setState({value: e.target.value})}
   />

Adjust the visibility of the dropdown based on the length of the entered value.

  handleVisibleChange = (flag) => {
    if(this.state.value.length <= 0)
     this.setState({ visible: false });
    else
     this.setState({ visible: flag });
  };

Complete code example:

import React from "react";
import ReactDOM from "react-dom";
import "antd/dist/antd.css";
import "./index.css";
import { Menu, Dropdown, Input } from "antd";

class OverlayVisible extends React.Component {
  state = {
    visible: false,
    value: ''
  };

  handleMenuClick = (e) => {
    if (e.key === "3") {
      this.setState({ visible: false });
    }
  };

  handleVisibleChange = (flag) => {
    if(this.state.value.length<=0)
    this.setState({ visible: false });
    else
    this.setState({ visible: flag });
  };

  render() {
    const menu = (
      <Menu onClick={this.handleMenuClick}>
        <Menu.Item key="1">Clicking me will not close the menu.</Menu.Item>
      </Menu>
    );
    return (
      <Dropdown
        onClick={() => {
          this.setState({ visible: true });
        }}
        overlay={menu}
        onVisibleChange={this.handleVisibleChange}
        visible={this.state.visible}
        trigger={["click"]}
      >
        <Input.Search
          onInput={() => {
            this.setState({ visible: true });
          }}
          onChange={e => this.setState({value: e.target.value})}
        ></Input.Search>
        {/* <a className="ant-dropdown-link" onClick={e => e.preventDefault()}>
          Hover me <Icon type="down" />
        </a> */}
      </Dropdown>
    );
  }
}

ReactDOM.render(<OverlayVisible />, document.getElementById("container"));

Answer №6

Adding my personal experience to @raqibrasheed 786's solution. I encountered a similar issue with controlling the open status of a dropdown menu while attempting to create a multiselect feature with checkbox items.

type MultiSelectProps = {
  options: Array<{ value: string, label: string }>;
} & Partial<DropdownProps>;

export const MultiSelect: React.FC<MultiSelectProps> = ({
  options,
}) => {
  const handleOnClickOption = (e: any, val: string) => {
    // This is crucial to prevent event propagation and keep the menu open.
    e.stopPropagation();
    // Define the action for clicking each menu item.
  };

  const ignoreHandler = (e: any) => e.preventDefault();

  const menu = (<Menu
    items={options?.map(option => ({
      key: option.value,
      label:
        <div
          role="button"
          onClick={(e) => handleOnClickOption(e, option.value)}
        >
          {/* Your component to render the menu item, ignoring click events from children */}
          <Checkbox
            checked={!!Math.floor(Math.random() + 1)}
            onClick={ignoreHandler}
          />
        </div>
    }))}
  />);

  return (
    <Dropdown
      className=""
      overlay={menu}
      trigger={["click"]}
    >
      {/* Render something based on current status */}
    </Dropdown>
  );
};

The main takeaways:

  • Avoid triggering child items
  • Prevent propagation within the menu item wrapper

This approach helps maintain the menu open with a single click event.

Answer №7

If you want to take control of the dropdown yourself using the open state, here are some example codes for you:

const [open, setOpen] = useState<boolean>(true);
<Dropdown menu={{ items }} 
   open={open} 
   onOpenChange={(open) => {
     // manage the open state according to your needs
     // if you prefer to keep the dropdown open, simply do nothing and it will stay open 
    }}>
    <a onClick={(e) => e.preventDefault()}>
      <Space>
        Cascading menu
        <DownOutlined />
      </Space>
    </a>
  </Dropdown>

You can also refer to this sandbox example

Answer №8

If you're looking for a solution, consider trying the following approach:

  • Implement custom isOpen and setIsOpen functions.
  • Create a wrapper with a container that has an ID, like <div id={dropDownId} />, and attach an onClick event to it.
  • Set the prop getPopupContainer to bind the container as mentioned above.

This way, the <Dropdown /> component will always stay within the container.

import "./styles.css";
import { Button, Dropdown } from "antd";
import { useState } from "react";

export default function App() {
  const [isOpen, setOpen] = useState(false);

  const items = [
    {
      key: "1",
      label: "1",
      show: true,
    },
    {
      key: "2",
      label: "2",
      show: true,
    },
    {
      key: "3",
      label: "3",
      show: true,
    },
    {
      key: "4",
      label: "4",
      show: true,
    },
  ];

  const defaultSelectedKeys = items
    .filter((item) => item.show)
    .map((item) => item.key);

  const dropDownId = "drop-down-id";

  return (
    <div className="App">
      <div id={dropDownId} onClick={() => setOpen(!isOpen)}>
        <Dropdown
          open={isOpen}
          menu={{
            getPopupContainer: () => 
 document.getElementById(dropDownId) as HTMLDivElement,
            selectable: true,
            multiple: true,
            onClick: ({ domEvent }) => {
              domEvent.stopPropagation();
            },
            items, // ...
            defaultSelectedKeys, // ...
          }}
        >
          <Button type="primary">show buttons</Button>
        </Dropdown>
      </div>
    </div>
  );
}

Check out the sandbox example demo

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

Javascript's feature that allows for loading more content dynamically

EDIT: Initially, this question was too general. What I really need is a detailed tutorial on how to implement the Load More function specifically for Safari on the iPhone, similar to how it works on the Twitter mobile website (mobile.twitter.com). Just usi ...

Even when using a conditional statement in JavaScript, Firebase continues to make multiple calls

I am in the process of creating an application using Vue.js and Firebase. Despite being new to Firebase, I have encountered some issues that I am struggling with. Specifically, I am trying to store names and email addresses in the database. My goal is to f ...

Is there a way to prevent the update status function from refreshing when the dropdownlist is changed in MVC?

Refreshing only the corresponding row when clicking on the status update is essential. Prior to that, I have implemented a dropdown onchange function which determines which table rows are displayed. cs.html: <section class="card "> < ...

What is the optimal resolution for a background image in a Cordova app?

Currently working on a Cordova application that requires different background images for various screens. Despite using media queries to provide the background image in different resolutions, we are facing an issue where the background image is not displ ...

What is the best way to store information in a React Native app for future use?

Can anyone assist me in developing a React Native application that is capable of storing data locally and then synchronizing it with the server? I would greatly appreciate any guidance on how to achieve this. ...

The dollar sign is not available during the onload event

Can someone help me with the error I am encountering where $ is unidentified when using onload on my page? This is a simple sample page created to call a function after the page has loaded. Jquery Code $(document).ready(function(){ alert("loaded"); }) ...

Trouble with Executing a JavaScript Function

Struggling to get a particular method to run, I initially had success when the JavaScript was embedded within the HTML file. However, after shifting the JavaScript code into an external file, the method seems unresponsive: Here is my html snippet: <he ...

"Is there a way to retrieve the dropdown text instead of the value from Request.Form() in ASP

I'm currently working with MVC 4.0 and facing an issue. It seems I need to access the text of a dropdown box (not just the value) by using Request.Form("ddlId") in my controller code. The goal is to display the selected information on a confirmation ...

Understanding the Distinction Between Arrays and Objects in Javascript. How can we differentiate between arrays and objects, and when do arrays inherit array-specific methods?

Although I have experience in C/C++/PIC assembly and VHDL, I am struggling with JavaScript. Currently, I am developing a single page application in React, but my question is more about improving my understanding rather than fixing an issue (as I have alrea ...

Utilizing jQuery to access data retrieved from ajaxStop

Seeking help on retrieving the json data returned from ajaxStop... I have tried accessing the data property within the event object, but it shows as undefined even though the data is being returned correctly... Cheers, Anthony UPDATE: Upon using Succes ...

I find the JSX syntax to be quite perplexing

While examining some code, I came across the following: const cardSource = { beginDrag(props) { return { text: props.text }; } }; When working with JSX block code or building objects, I usually use {}. The cardSource variable in this co ...

Where did my context provider namespace disappear to?

Why is Intellisense throwing an error saying it can't find the namespace WorkorderListContext in the WorkorderListProvider return, even though they are both in the same file? import { createContext } from 'react'; interface IWorkorderListCo ...

Utilizing responsive font sizing in material-ui: A step-by-step guide

My theme provider is functioning as expected, but the typography settings seem to be causing issues. Below is the theme provider code that has already been imported into the App file: import { createTheme } from '@mui/material/styles'; export c ...

The JavaScript functionality is disrupted by the getCurrentPosition function on the Chrome

I'm having an issue with my webpage that displays Google Maps. I am using getCurrentPosition over http and receiving a warning from the Google API. The problem is that it's also breaking the JavaScript, which then ruins everything. This code was ...

Is there a way to eliminate a tag that includes all attributes except for certain ones?

Here is the code I am working with: var str = `<p>paragraph<a>link</a></p> <div class="myclass"> <div>something</div> <div style="mystyle">something</div> ...

Dealing with multiple input fields that are generated using the map method in combination with react-redux

I am working on a project where I have a product list in JSON format stored in json-server. I am using React-Redux to fetch the data and render it in a table. Additionally, I have an input field where users can enter the quantity of each product. I need to ...

Error Encountered: Nested textarea not supported in HTML

Below is the code I am working with. The issue lies with the <textarea>. In my form, there is a textarea. When I insert another <textarea> within the ckeditor value (HTML), the inner textarea ends up closing the parent textarea. Is there a sol ...

Transform JSON reply in JavaScript/Typescript/Angular

Looking for assistance with restructuring JSON data received from a server API for easier processing. You can find the input JSON file at assets/input-json.json within the stackblitz project: https://stackblitz.com/edit/angular-ivy-87qser?file=src/assets/ ...

Can RethinkDB and Node.js/Express handle parallel queries with multiple connections?

Is there a more efficient method for running parallel queries with the RethinkDB Node driver without opening multiple connections per request? Or is this current approach sufficient for my needs? I'd like to avoid using connection pools or third-party ...

Unusual sizing of text input in jQuery Mobile

I've encountered an issue regarding the width of a text input in jQuery Mobile - it appears to be too large. <div data-role="page"> <div data-role="header"> <h1>Test</h1> </div> <div data-role="co ...