technicallynick
technicallynick

Reputation: 1592

onClick function firing without click

I've got an extremely basic setup of a Button and a Dialog. The Dialog open state is opened via an onClick function on Button. The Dialog has a hidden input field. When the user inputs text and hits 'Enter', the dialog should close and a search function is initiated.

The problem I'm experiencing is that when 'Enter' is hit, the onClick function on the button is also triggered. So, I can see in the logs that the dialog is closed, search function is initiated, and the dialog is immediately reopened.

 const handleClose = () => {
    console.log("closing dialog");
    updateState({
      showDialog: false
    });
  };

  const handleKeyDown = ({ key, target: { value } }) => {
    if (key === "Enter") {
      console.log("Enter hit!");
      handleClose();
      searchForLocalEntries(value);
    }
  };

  const handleOpen = () => {
    console.log("opening dialog!");
    updateState({
      showDialog: true
    });
  };

  const handleChange = ({ target: { value } }) => {
    setInputValue(value);
  };

return (
    <>
      <Button
        color="secondary"
        type="button"
        variant="contained"
        onClick={handleOpen}
      >
        <AddIcon className={classes.largeButtonIcon} />
      </Button>
      <Dialog
        fullScreen={fullScreen}
        open={state.showDialog}
        onClose={handleClose}
        classes={{ paper: classes.AddToInventoryRoot }}
      >
       <DialogContent>
         ...
       </DialogContent>
      </Dialog>
    </>
  );

Any help on what I'm missing here would be greatly appreciated!

Edit Dialog_Example

Upvotes: 1

Views: 987

Answers (1)

Ryan Cogswell
Ryan Cogswell

Reputation: 81106

The fix is easy enough. Calling event.preventDefault() when key === "Enter" (which prevents the "default" browser behavior of triggering a click when Enter is hit on a button):

  const handleKeyDown = event => {
    const {
      key,
      target: { value }
    } = event;
    if (key === "Enter") {
      event.preventDefault();
      console.log("Enter hit!");
      handleClose();
      searchForLocalEntries(value);
    }
  };

Edit Dialog_Example

The reason why that is necessary is a little less straightforward. When you hit Enter the dialog is closing and focus is moving from the hidden input back to the button. The browser appears to use the element that ends up with focus when deciding whether to trigger a click event on Enter.

Below is an example that shows this aspect in isolation. Hitting Enter within the input moves focus to the button. The second input has event.preventDefault(); added to see the difference with and without this fix. For the first input, the click is registered on the button (shown by the increment of the count) when Enter is hit within the input.

import React from "react";

export default function App() {
  const buttonRef1 = React.useRef();
  const buttonRef2 = React.useRef();
  const [count1, setCount1] = React.useState(0);
  const [count2, setCount2] = React.useState(0);
  const handleKeyDown1 = event => {
    if (event.key === "Enter") {
      buttonRef1.current.focus();
    }
  };
  const handleKeyDown2 = event => {
    if (event.key === "Enter") {
      event.preventDefault();
      buttonRef2.current.focus();
    }
  };
  return (
    <div className="App">
      <input onKeyDown={handleKeyDown1} />
      <br />
      <button onClick={() => setCount1(count1 + 1)} ref={buttonRef1}>
        I get focus when you hit Enter in the input
      </button>{" "}
      Count: {count1}
      <br />
      <br />
      <input onKeyDown={handleKeyDown2} />
      <br />
      <button onClick={() => setCount2(count2 + 1)} ref={buttonRef2}>
        I get focus when you hit Enter in the input
      </button>{" "}
      Count: {count2}
    </div>
  );
}

Edit show button click on enter after focus change

Related documentation: https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault

Upvotes: 4

Related Questions