Reputation: 1592
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!
Upvotes: 1
Views: 987
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);
}
};
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>
);
}
Related documentation: https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault
Upvotes: 4