javascriptreactjsbuttonreact-select

Custom SingleValue Button Not Clickable


I am trying to add an edit button (which currently triggers an alert) to my react-select component. However, this makes the newly added button unclickable; instead, it opens the react-select menu. Stopping propagation does not solve the issue.

const CustomOption = (props) => {
  const handleEdit = (e) => {
    e.stopPropagation();
    alert("This is working like I want");
  };

  return (
    <components.Option {...props}>
      <div className="test">
        <span>{props.children}</span>
        <button onClick={handleEdit}>Edit</button>
      </div>
    </components.Option>
  );
};
export default function App() {
  const option = [
    { value: "Spring", label: "Spring" },
    { value: "Summer", label: "Summer" },
    { value: "Autumn", label: "Autumn" },
    { value: "Winter", label: "Winter" },
  ];

  return (
    <div className="App">
      <Select
        className="dropdown"
        options={option}
        components={{ SingleValue: CustomSingleValue }}
      />
    </div>
  );
}

Question: Why doesn't the button inside CustomSingleValue work (while the one inside CustomOption does), and how can I fix it?

Code SandBox

This is especially frustrating because CustomOption, which uses the exact same code, works fine.

Working vs not working

Full code including working CustomOption:

// This isn't working like I want
const CustomSingleValue = (props) => {
  const handleEdit = (e) => {
    e.stopPropagation();
    alert("This I can't click");
  };

  return (
    <components.SingleValue {...props}>
      <div className="test">
        <span>{props.children}</span>
        <div>
          <button onClick={handleEdit}>Edit</button>
        </div>
      </div>
    </components.SingleValue>
  );
};

// This is working how I want
const CustomOption = (props) => {
  const handleEdit = (e) => {
    e.stopPropagation();
    alert("This is working like I want");
  };

  return (
    <components.Option {...props}>
      <div className="test">
        <span>{props.children}</span>
        <button onClick={handleEdit}>Edit</button>
      </div>
    </components.Option>
  );
};
export default function App() {
  const option = [
    { value: "Spring", label: "Spring" },
    { value: "Summer", label: "Summer" },
    { value: "Autumn", label: "Autumn" },
    { value: "Winter", label: "Winter" },
  ];

  return (
    <div className="App">
      <Select
        className="dropdown"
        options={option}
        placeholder="Click on a option and then try to click the edit button"
        components={{ SingleValue: CustomSingleValue, Option: CustomOption }}
      />
    </div>
  );
}

Solution

  • Issue number one: you have a react-select input overlayed your component, hence you click it instead of your single value component:

    devtools cannot lie

    To address that, you need to add z-index:

    const singleValueStyles = {
      singleValue: (styles) => ({ ...styles, "z-index": 2 }),
    };
    ...
    
    <Select
      className="dropdown"
      options={option}
      styles={singleValueStyles} // 👈
    ...
    
    

    After that, the button works well, however, we still get the dropdown opened. That's because react-select uses onMouseDown rather that onClick. The easiest way to fix it is to use onMouseDown too:

    <button onMouseDown={handleEdit}>Edit</button>
    

    If you want to keep onClick, just add another handler for onMouseDown that only stops propagation.