I'd like to get a TextField to select the whole text currently in the field whenever I click/tap/focus on the field. The following code works in Chrome (71.0.3578.98), but not in Safari (12.0.2). Any ideas why?
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
function App() {
return (
<>
<h1>Test Focus React</h1>
<input
type="text"
defaultValue="test"
onFocus={event => {
event.target.select();
}}
/>
</>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
And yet this static HTML file without any React works fine on Safari.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Test Focus JS</title>
</head>
<body>
<h1>Test Focus JS</h1>
<input type="text" value="test" onClick="this.select();" />
</body>
</html>
Can anyone help me see how to get the selection to work on Safari with React?
When things like interacting with the DOM fail, it usually is related to how events fire synchronously / asynchronously in different contexts (react vs onclick), and browsers even (with Safari having weird optimisations sometimes).
I'm guessing it'll just work by making it async, like:
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
function App() {
return (
<>
<h1>Test Focus React</h1>
<input
type="text"
defaultValue="test"
onFocus={event => {
// event properties must be copied to use async
const target = event.target;
setTimeout(() => target.select(), 0);
}}
/>
</>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
This is well known issue, you can work around this basically using set timeout
onFocus={event => {
setTimeout(event.target.select.bind(event.target), 20);
}}
Here is working example. I tested on safari worked without any issue.
I think you want to use a React ref
to store a reference to the actual input
DOM element so that you can call select
on it from the onClick
method.
See the docs, they have a good example that you can modify a little bit to meet your needs: https://reactjs.org/docs/refs-and-the-dom.html
This should work, I think:
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
class CustomTextInput extends React.Component {
constructor(props) {
super(props);
this.textInput = React.createRef();
this.selectTextInput = this.selectTextInput.bind(this);
}
selectTextInput() {
this.textInput.current.select();
}
render() {
return (
<div>
<input
type="text"
defaultValue="pizza"
ref={this.textInput}
onClick={this.selectTextInput}
/>
</div>
);
}
}
function App() {
return (
<CustomTextInput />
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);