Working in React 17.0.2
I have a single input on a page; I’ve tried type="password" and type="input". Only added second input in to test what happens if there’s more than one. Also used a text input.
I have a button.
I have a keydown eventListener listening for ‘Enter’.
On Enter click I check the document.activeElement. If the activeElement is the input, I blur(). If the activeElement is the button, I return false;
If neither are the activeElement (essentially if body is the activeElement), then I document.querySelector() for the button and trigger a .click()
The page refreshes as soon as the code hits the .focus()
If I comment the focus() out, no refresh.
If there are multiple inputs on the page I do a querySelectorAll(), grab the first field and focus. No refresh, that first field focuses just fine.
The html is all in a form, the form submit is handled via later functionality, I’m not including all of that here as the form does not submit in any other circumstance except when there is a single input on the page and I hit Enter and the eventListener captures the click and focuses on that input.
Things I have tried to prevent this:
- Used jQuery.
- Added an event listener for
focus and added event.preventDefault() as well as return false
Same happens in Chrome, Firefox, Edge.
Here’s some of my code:
Input
<input
id="password"
name="password"
type="text"
/>
Button
<button
className={`btn 'btn-primary' js-enter-click`}
id='next'
onClick={(event) => handleNextClick(event)}
onKeyDown={(event) => handleNextKeyDown(event)}
ref={buttonNextRef}
type="button"
>
Continue
</button>
Button handlers
// Prevent React from triggering two onClicks when a button has focus and Enter is pressed
const handleNextKeyDown = (event) => {
if (event.key === 'Enter') {
event.preventDefault();
handleNextClick(event);
}
};
// Handle the next button click
const handleNextClick = (event) => {
event.preventDefault();
focusFirstInvalidField();
}
Focus on a field function
NOTE: this used to have code that was testing for validation etc but I stripped it all out to make debugging simple
// Focus on the first invalid/empty field
focusFirstInvalidField: function() {
const invalidFields = document.querySelectorAll('input:enabled:not([type="hidden"]):not([type="button"]), select:enabled');
// if there is only a single field on the page, try adding an eventlistener to listen for the focus event
// then as we focus on the field, try preventDefault() to prevent the page from reloading
// NOTE this doesn't prevent the refresh
if (invalidFields.length === 1) {
invalidFields[0].addEventListener('focus', (event) => {
event.preventDefault();
return false;
});
// This focus causes a refresh.
invalidFields[0].focus();
} else {
// Also have tried looping through all the fields, then focusing. If only one field, refresh happens.
for (const field of invalidFields) {
// As soon as the code hits this line poof refresh. Comment it out, no refresh.
field.focus();
break;
}
}
}
Event Listener
document.addEventListener('keydown', function(e) {
if (e.key === 'Enter') {
// Check if we're in a field with focus first, and blur it, then return out of this function.
if (document.activeElement &&
document.activeElement.tagName === 'INPUT' ||
document.activeElement.tagName === 'SELECT' ||
document.activeElement.tagName === 'TEXTAREA'
) {
document.activeElement.blur();
return false;
} else if (document.activeElement.classList.contains('.btn')) {
// If the activeElement is a button, return false. Each action button should have an onKeyPress that handles the enter key and triggers the onClick handler.
return false;
}
const next = document.querySelector('.js-enter-click');
// Click the next button if it exists and is not disabled
next && next.click();
// prevent further activity
return false;
}
});