I'm in the process of building a customised, accessible select input with React.js. I need to have the up and down arrow keys function as the tab key would within the scope of select input's options.
I have a handleKeyPress function on the elements that detects when other keys are pressed (for instance 'Enter' works fine).
Here is an example option:
<li
className="oc-select-field__item"
tabIndex="0"
onClick={handleClick}
onKeyPress={handleKeyPress}
>
...and here is the handleKeyPress function
handleKeyPress = event => {
if (event.key === 40) {
console.log('Down arrow key fired'); // does not fire
}
if (event.key === 'Enter') {
console.log('Enter key fired'); // does fire
}
};
What am I doing wrong that I am not successfully detecting when the down arrow is pressed?
event.which will give you the numeric value of the key.
event.key and event.code will give you a string value.
Try this tool: http://keycode.info
if (event.key === 'ArrowDown') {
console.log('Down arrow key fired');
}
As #devserkan mentioned you should use onKeyDown instead of onKeyPress.
The keydown event is fired when a key is pressed down. Unlike the keypress event, the keydown event is fired for keys that produce a character value and for keys that do not produce a character value.
For Arrow keys, I think you need onKeyDown instead of onKeyPress.
class App extends React.Component {
handleKeyPress = ( event ) => {
if ( event.key === "ArrowDown" ) {
console.log( "Down arrow key fired" ); // does not fire
}
if ( event.key === "Enter" ) {
console.log( "Enter key fired" ); // does fire
}
};
render() {
return (
<div>
<ul>
<li
tabIndex="0"
onClick={this.handleClick}
onKeyDown={this.handleKeyPress}
>Foo
</li>
</ul>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Related
I have a input for searchbox. I must make like; Write my words fors search then after i press enter it must need go another page with input value. So i can access that value with query string. So how can i route another page with value of input after i press enter ? Thank you for help! I Just add That codes for catch enter press.
useEffect(() => {
const listener = (event) => {
if (event.code === "Enter" || event.code === "NumpadEnter") {
alert("Enter key was pressed. Run your function.");
event.preventDefault();
}
};
document.addEventListener("keydown", listener);
return () => {
document.removeEventListener("keydown", listener);
};
}, []);
You don't necessarily have to set an event listener, using onKeyDown event handler will also do. Enter key has a code of 13, so we just have to detect that.
Keep your value in a state (here, myValue), detect that you've pressed Enter key (here, using keyPressHandler method), and finally, pass the parameter to your route.
import {useHistory} from "react-router-dom"
function App() {
let history = useHistory();
const [myValue, setMyValue] = useState("");
const handleChange = ({ target: { value } }) => {
setMyValue(value);
};
const keyPressHandler = (e) => {
if (e.which === 13) {
// alert("You pressed enter!");
history.push("/process/" + myValue);
}
};
return (
<div className="App">
<input value={myValue} onKeyDown={keyPressHandler} onChange={handleChange} />
</div>
);
}
UPDATE:
According to MDN Web Docs, e.which is non-standard [Source] and e.keyCode is deprecated [Source], so you should be using e.key instead like:
const keyPressHandler = (e) => {
if (e.key=== 'Enter') {
// alert("You pressed enter!");
history.push("/process/" + myValue);
}
};
Working CodeSandbox Link
I have a button that can be highlighted with Tab, where pressing Enter when the button is highlighted creates an Input field. That input field is then focused.
The input field has a keyUp event and if the key is Enter/Return, blur the field (and save the info that was put into the field).
The issue:
Tab to select Button
Keydown Enter/Return to create Input field
Input field is now focused
Keyup Enter/Return
Input becomes blurred
What I need is to know if the enter/return key was pressed on mount and stop the Keyup event from firing if that is true.
export default function EditableLabel({
active,
value: valueProp,
variant,
...rest
}) {
const [returnPressedOnMount, setReturnPressedOnMount] = useState(false);
let isReturnPressed = false;
// Only set this listener on mount
useEffect(() => {
document.addEventListener('keypress', isReturnKey, false);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
function isReturnKey(event) {
console.log(event.keyCode);
if (!returnPressedOnMount && event.keyCode === 13) {
console.log('In the return key func');
setReturnPressedOnMount(true);
isReturnPressed=true;
console.log(isReturnPressed)
}
document.removeEventListener('keypress', isReturnKey, false);
}
function handleBlur(evt) {
setIsEditing(false);
rest.onChange && rest.onChange({ target: { value } });
rest.onBlur && rest.onBlur(evt);
}
function handleKeyUp(evt) {
console.log(returnPressedOnMount);
console.log(isReturnPressed);
if (evt.key === 'Enter') {
if (!returnPressedOnMount) {
const target = evt.target;
setTimeout(() => target.blur(), 0);
} else {
setReturnPressedOnMount(false);
}
}
rest.onKeyUp && rest.onKeyUp(evt);
}
return (
<Input .../>
);
}
This code works if I hold the Enter/Return key down for a long time, but if someone presses the key normally (just tap the key, not holding it down) the State/Variable do not update in time for the onKeyUp.
How do I get the knowledge of the Return key being pressed on Mount to the onKeyUp function?
I can get the onKeyPress event to fire from the canvas
<canvas
id='canvas'
ref={canvasRef}
className='canvas'
tabIndex={0}
onKeyPress={(e: React.KeyboardEvent) => setKeyDown(e)}
/>
But the setKeyDown function thst recieves the event doesnt seem to fire when I press delete while other keys do log values, I want to know if the delete key was pressed.
const setKeyDown = (event: React.KeyboardEvent<Element>) => {
console.log(event.keyCode);
console.log(event.key);
};
I have tried using any as the type but I get the same results
onKeyPress doesn't capture the delete key. To capture delete key presses use onKeyDown event.
onKeyDown={(e: React.KeyboardEvent) => setKeyDown(e)}
You need to capture onKeyDown event
your event handler be like
onDelete = (e) => {
if (e.keyCode === 46) {
alert(e.keyCode);
}
};
Keycode for delete key is 46
I have a React Modal that opens and closes via a handler function.
I'd like to call that function with either a click event or with the use of the esc key for accessibility proposes.
How could I track both events at the same time?
So far I got the esc event as:
handleCloseModal = event => {
if (event.keyCode === 27) {
this.setState({ modal: false })
}
}
But then I lose the click functionality on
<Modal
onClick={handleCloseModal}
role="button" tabIndex={0}
onKeyDown={handleCloseModal}
/>
How should I go about this?
One possible solution can be: Create a separate function to close the Modal. Use that function for onClick and call it when esc key pressed.
Like this:
<Modal
onClick={handleCloseModal}
role="button" tabIndex={0}
onKeyDown={handleKeyDown}
/>
handleKeyDown = event => {
if (event.keyCode === 27) {
handleCloseModal()
}
}
handleCloseModal = () => this.setState({ modal: false })
If I understand correctly, you're wanting to reuse the same close event handler for both click and keydown event types. One way to distinguish between these two event types would be to detect the event object's type via instanceof as follows:
handleCloseModal = event => {
// if event is mouse event, handle it accordingly
if(event instanceof MouseEvent) {
// if mouse click detected hide the modal
this.setState({ modal: false })
}
// if event is keyboard event, handle it accordingly
else if(event instanceof KeyboardEvent) {
// if escape key pressed for keyboard event then hide the modal
if (event.keyCode === 27) {
this.setState({ modal: false })
}
}
}
I have an <input/> which defines an onKeyDown prop which is fired when a key is pressed. In the callback, I check if the keycode matches a certain key (in this case, the up or down arrow keys).
I need to notify a sibling component that is in the same render() method as the <input/> whenever one of the matching keys is pressed.
Here is the relevant code:
handleKey(e) {
let keyCode = e.keyCode;
//Handle up arrow press.
if (keyCode == 38) {
console.log('up arrow pressed')
}
//Handle down arrow press.
if (keyCode == 40) {
console.log('down arrow pressed')
}
}
render() {
return (
<div className="chat-input">
{this.state.showCommandPopup && <CommandPopup input={this.state.inputValue}/> }
<form onSubmit={this.handleSubmit.bind(this)}>
<Input onKeyDown={this.handleKey.bind(this)} value={this.state.inputValue} onChange={this.onInputChange.bind(this)} className="chat-input-comp" placeholder="Say something. You can use / to search, and . for commands." action='Send'/>
//....
</form>
</div>
);
}
How can I notify my <CommandPopup/> component whenever the up or down arrow key is pressed?
Step 1.
You need to call setState inside handleKey() method. Once setState is called parent as well as child component will re-render.
handleKey(e) {
let keyCode = e.keyCode;
//Handle up arrow press.
if (keyCode == 38) {
this.setState({keyvalue:keyCode})
console.log('up arrow pressed')
}
//Handle down arrow press.
if (keyCode == 40) {
console.log('down arrow pressed')
this.setState({keyvalue:keyCode})
}
// It will call render() Method
}
Step 2.
Inside CommandPopup component you need to add, componentWillReceiveProps(newProps).
Inside componentWillReceiveProps(newProps), you will get the updated value of input={this.state.inputValue}
componentWillReceiveProps(newProps){
console.log(newProps.keyvalue,'keycode')
}
You just need to raise an event, nothing prevents you to use js events. But I think you are not doing the proper way, since react is not an event base framework, and there is maybe a better solution to this problem using a state container like redux or mobx.
On your CommandPopup component you just need to subscribe to the event.
class CommandPopup extends Component {
componentDidMount() {
window.addEventListener('keyUp', () => {
console.log('Key UP ...');
});
window.addEventListener('keyDown', () => {
console.log('Key DOWN ....');
});
}
render() {
return (
<div>Something ...</div>
);
}
}
And just dispatch the event:
handleKey(e) {
let keyCode = e.keyCode;
//Handle up arrow press.
if (keyCode == 38) {
const ev = new Event('keyUp', { 'bubbles': true, 'cancelable': false });
document.dispatchEvent(ev);
}
//Handle down arrow press.
if (keyCode == 40) {
const ev = new Event('keyDown', { 'bubbles': true, 'cancelable': false });
document.dispatchEvent(ev);
}
}
render() {
return (
<div className="chat-input">
{this.state.showCommandPopup && <CommandPopup input={this.state.inputValue}/> }
<form onSubmit={this.handleSubmit.bind(this)}>
<Input onKeyDown={this.handleKey.bind(this)} value={this.state.inputValue} onChange={this.onInputChange.bind(this)} />
</form>
</div>
);
}
Again maybe you should take a look to mobx computed values, this is the kind of problem they can solve.
Hope this help.