Reputation: 11862
What's the react way of setting focus on a particular text field after the component is rendered?
Documentation seems to suggest using refs, e.g:
Set ref="nameInput"
on my input field in the render function, and then call:
this.refs.nameInput.getInputDOMNode().focus();
But where should I call this? I've tried a few places but I cannot get it to work.
Upvotes: 990
Views: 1132137
Reputation: 8271
As of React 0.15, the most concise method is:
<input ref={input => input && input.focus()}/>
Upvotes: 236
Reputation: 19816
React 16.3 added a new convenient way to handle this by creating a ref in component's constructor and use it like below:
class MyForm extends Component {
constructor(props) {
super(props);
this.textInput = React.createRef();
}
componentDidMount() {
this.textInput.current?.focus();
}
render() {
return(
<div>
<input ref={this.textInput} />
</div>
);
}
}
For more details about React.createRef
, you can check this article in React blog.
Update:
Starting from React 16.8, useRef
hook can be used in function components to achieve the same result:
import React, { useEffect, useRef } from 'react';
const MyForm = () => {
const textInput = useRef(null);
useEffect(() => {
textInput.current?.focus();
}, []);
return (
<div>
<input ref={textInput} />
</div>
);
};
Upvotes: 66
Reputation: 26608
If you just want to focus an element when it mounts (initially renders) a simple use of the autoFocus attribute will do.
<input type="text" autoFocus />
to control focus dynamically use a general function to hide implementation details from your components.
const FocusDemo = () => {
const [inputRef, setInputFocus] = useFocus()
return (
<>
<button onClick={setInputFocus} >
Focus
</button>
<input ref={inputRef} />
</>
)
}
const useFocus = () => {
const htmlElRef = useRef(null)
const setFocus = () => {htmlElRef.current && htmlElRef.current.focus()}
return [ htmlElRef, setFocus ]
}
class App extends Component {
constructor(props){
super(props)
this.inputFocus = utilizeFocus()
}
render(){
return (
<>
<button onClick={this.inputFocus.setFocus}>
Focus
</button>
<input ref={this.inputFocus.ref}/>
</>
)
}
}
const utilizeFocus = () => {
const ref = React.createRef()
const setFocus = () => {ref.current && ref.current.focus()}
return {setFocus, ref}
}
Upvotes: 367
Reputation: 804
Focus using createRef for functional components
To developers using Functional Components. This seems to suit. Focus happens on inputfield after clicking on the button. I've attached CodeSandbox link too.
import React from 'react';
export default function App() {
const inputRef = React.createRef();
return <>
<input ref={inputRef} type={'text'} />
<button onClick={() => {if (inputRef.current) { inputRef.current.focus() }}} >
Click Here
</button>
</>
}
https://codesandbox.io/s/blazing-http-hfwp9t
Upvotes: 1
Reputation: 155
Ben Carp solution in typescript
React 16.8 + Functional component - useFocus hook
export const useFocus = (): [React.MutableRefObject<HTMLInputElement>, VoidFunction] => {
const htmlElRef = React.useRef<HTMLInputElement>(null);
const setFocus = React.useCallback(() => {
if (htmlElRef.current) htmlElRef.current.focus();
}, [htmlElRef]);
return React.useMemo(() => [htmlElRef, setFocus], [htmlElRef, setFocus]);
};
Upvotes: 4
Reputation: 2353
Simple solution without autofocus:
<input ref={ref => ref && ref.focus()}
onFocus={(e)=>e.currentTarget.setSelectionRange(e.currentTarget.value.length, e.currentTarget.value.length)}
/>
ref
triggers focus, and that triggers onFocus
to calculate the end and set the cursor accordingly.
Upvotes: 3
Reputation: 9524
Using React Hooks / Functional components with Typescript, you can use the useRef
hook with HTMLInputElement
as the generic parameter of useRef
:
import React, { useEffect, useRef } from 'react';
export default function MyComponent(): JSX.Element {
const inputReference = useRef<HTMLInputElement>(null);
useEffect(() => {
inputReference.current?.focus();
}, []);
return (
<div>
<input ref={inputReference} />
</div>
);
}
Or if using reactstrap
, supply inputReference
to innerRef
instead of ref
:
import React, { useEffect, useRef } from 'react';
import { Input } from 'reactstrap';
export default function MyComponent(): JSX.Element {
const inputReference = useRef<HTMLInputElement>(null);
useEffect(() => {
inputReference.current?.focus();
}, []);
return (
<div>
<Input innerRef={inputReference} />
</div>
);
}
Upvotes: 14
Reputation: 630
Since there is a lot of reasons for this error I thought that I would also post the problem I was facing. For me, problem was that I rendered my inputs as content of another component.
export default ({ Content }) => {
return (
<div className="container-fluid main_container">
<div className="row">
<div className="col-sm-12 h-100">
<Content /> // I rendered my inputs here
</div>
</div>
</div>
);
}
This is the way I called the above component:
<Component Content={() => {
return (
<input type="text"/>
);
}} />
Upvotes: -1
Reputation: 283203
To move focus to a newly created element, you can store the element's ID in the state and use it to set autoFocus
. e.g.
export default class DefaultRolesPage extends React.Component {
addRole = ev => {
ev.preventDefault();
const roleKey = this.roleKey++;
this::updateState({
focus: {$set: roleKey},
formData: {
roles: {
$push: [{
id: null,
name: '',
permissions: new Set(),
key: roleKey,
}]
}
}
})
}
render() {
const {formData} = this.state;
return (
<GridForm onSubmit={this.submit}>
{formData.roles.map((role, idx) => (
<GridSection key={role.key}>
<GridRow>
<GridCol>
<label>Role</label>
<TextBox value={role.name} onChange={this.roleName(idx)} autoFocus={role.key === this.state.focus}/>
</GridCol>
</GridRow>
</GridSection>
))}
</GridForm>
)
}
}
This way none of the textboxes get focus on page load (like I want), but when you press the "Add" button to create a new record, then that new record gets focus.
Since autoFocus
doesn't "run" again unless the component gets remounted, I don't have to bother unsetting this.state.focus
(i.e. it won't keep stealing focus back as I update other states).
Upvotes: 3
Reputation: 3057
After trying a lot of options above with no success I've found that It was as I was disabling
and then enabling
the input which caused the focus to be lost.
I had a prop sendingAnswer
which would disable the Input while I was polling the backend.
<Input
autoFocus={question}
placeholder={
gettingQuestion ? 'Loading...' : 'Type your answer here...'
}
value={answer}
onChange={event => dispatch(updateAnswer(event.target.value))}
type="text"
autocomplete="off"
name="answer"
// disabled={sendingAnswer} <-- Causing focus to be lost.
/>
Once I removed the disabled prop everything started working again.
Upvotes: 2
Reputation: 86260
@Dhiraj's answer is correct, and for convenience you can use the autoFocus prop to have an input automatically focus when mounted:
<input autoFocus name=...
Note that in jsx it's autoFocus
(capital F) unlike plain old html which is case-insensitive.
Upvotes: 1236
Reputation: 104870
You don't need getInputDOMNode
?? in this case...
Just simply get the ref
and focus()
it when component gets mounted -- componentDidMount...
import React from 'react';
import { render } from 'react-dom';
class myApp extends React.Component {
componentDidMount() {
this.nameInput.focus();
}
render() {
return(
<div>
<input ref={input => { this.nameInput = input; }} />
</div>
);
}
}
ReactDOM.render(<myApp />, document.getElementById('root'));
Upvotes: 10
Reputation: 946
This is the proper way, how to autofocus. When you use callback instead of string as ref value, it is automatically called. You got your ref available than without the need of touching the DOM using getDOMNode
render: function() {
return <TextInput ref={(c) => this._input = c} />;
},
componentDidMount: function() {
this._input.focus();
},
Upvotes: 13
Reputation: 694
AutoFocus worked best for me. I needed to change some text to an input with that text on double click so this is what I ended up with:
<input autoFocus onFocus={this.setCaretToEnd} value={this.state.editTodo.value} onDoubleClick={this.updateTodoItem} />
NOTE: To fix the issue where React places the caret at the beginning of the text use this method:
setCaretToEnd(event) {
var originalText = event.target.value;
event.target.value = '';
event.target.value = originalText;
}
Found here: https://coderwall.com/p/0iz_zq/how-to-put-focus-at-the-end-of-an-input-with-react-js
Upvotes: 5
Reputation: 121
I have same problem but I have some animation too, so my colleague suggest to use window.requestAnimationFrame
this is ref attribute of my element:
ref={(input) => {input && window.requestAnimationFrame(()=>{input.focus()})}}
Upvotes: 6
Reputation: 21
Read almost all the answer but didnt see a getRenderedComponent().props.input
Set your text input refs
this.refs.username.getRenderedComponent().props.input.onChange('');
Upvotes: 1
Reputation: 6948
Note that none of these answers worked for me with a material-ui TextField component. Per How to set focus to a materialUI TextField? I had to jump through some hoops to get this to work:
const focusUsernameInputField = input => {
if (input) {
setTimeout(() => {input.focus()}, 100);
}
};
return (
<TextField
hintText="Username"
floatingLabelText="Username"
ref={focusUsernameInputField}
/>
);
Upvotes: 13
Reputation: 33628
You should do it in componentDidMount
and refs callback
instead. Something like this
componentDidMount(){
this.nameInput.focus();
}
class App extends React.Component{
componentDidMount(){
this.nameInput.focus();
}
render() {
return(
<div>
<input
defaultValue="Won't focus"
/>
<input
ref={(input) => { this.nameInput = input; }}
defaultValue="will focus"
/>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react-dom.js"></script>
<div id="app"></div>
Upvotes: 810
Reputation: 5020
The simplest answer is add the ref="some name" in the input text element and call the below function.
componentDidMount(){
this.refs.field_name.focus();
}
// here field_name is ref name.
<input type="text" ref="field_name" />
Upvotes: 2
Reputation: 64
Updated version you can check here
componentDidMount() {
// Focus to the input as html5 autofocus
this.inputRef.focus();
}
render() {
return <input type="text" ref={(input) => { this.inputRef = input }} />
})
Upvotes: 0
Reputation: 8254
I just ran into this issue and I'm using react 15.0.1 15.0.2 and I'm using ES6 syntax and didn't quite get what I needed from the other answers since v.15 dropped weeks ago and some of the this.refs
properties were deprecated and removed.
In general, what I needed was:
I'm using:
I used autoFocus={true}
on the first <input />
on the page so that when the component mounts, it will get focus.
This took longer and was more convoluted. I'm keeping out code that isn't relevant to the solution for brevity.
I need a global state to know if I should set the focus and to disable it when it was set, so I don't keep re-setting focus when the components re-render (I'll be using componentDidUpdate()
to check for setting focus.)
This could be designed as you see fit for you application.
{
form: {
resetFocus: false,
}
}
The component will need to have the resetfocus
property set and a callBack to clear the property if it ends up setting focus on itself.
Also note, I organized my Action Creators into separate files mostly due to my project is fairly large and I wanted to break them up into more manageable chunks.
import { connect } from 'react-redux';
import MyField from '../presentation/MyField';
import ActionCreator from '../actions/action-creators';
function mapStateToProps(state) {
return {
resetFocus: state.form.resetFocus
}
}
function mapDispatchToProps(dispatch) {
return {
clearResetFocus() {
dispatch(ActionCreator.clearResetFocus());
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(MyField);
import React, { PropTypes } form 'react';
export default class MyField extends React.Component {
// don't forget to .bind(this)
constructor(props) {
super(props);
this._handleRef = this._handleRef.bind(this);
}
// This is not called on the initial render so
// this._input will be set before this get called
componentDidUpdate() {
if(!this.props.resetFocus) {
return false;
}
if(this.shouldfocus()) {
this._input.focus();
this.props.clearResetFocus();
}
}
// When the component mounts, it will save a
// reference to itself as _input, which we'll
// be able to call in subsequent componentDidUpdate()
// calls if we need to set focus.
_handleRef(c) {
this._input = c;
}
// Whatever logic you need to determine if this
// component should get focus
shouldFocus() {
// ...
}
// pass the _handleRef callback so we can access
// a reference of this element in other component methods
render() {
return (
<input ref={this._handleRef} type="text" />
);
}
}
Myfield.propTypes = {
clearResetFocus: PropTypes.func,
resetFocus: PropTypes.bool
}
The general idea is that each form field that could have an error and be focused needs to check itself and if it needs to set focus on itself.
There's business logic that needs to happen to determine if the given field is the right field to set focus to. This isn't shown because it will depend on the individual application.
When a form is submitted, that event needs to set the global focus flag resetFocus
to true. Then as each component updates itself, it will see that it should check to see if it gets the focus and if it does, dispatch the event to reset focus so other elements don't have to keep checking.
edit
As a side note, I had my business logic in a "utilities" file and I just exported the method and called it within each shouldfocus()
method.
Cheers!
Upvotes: 28
Reputation: 8489
The React docs now have a section for this. https://facebook.github.io/react/docs/more-about-refs.html#the-ref-callback-attribute
render: function() {
return (
<TextInput
ref={function(input) {
if (input != null) {
input.focus();
}
}} />
);
},
Upvotes: 30
Reputation: 18629
Warning: ReactDOMComponent: Do not access .getDOMNode() of a DOM node; instead, use the node directly. This DOM node was rendered by
App
.
Should be
componentDidMount: function () {
this.refs.nameInput.focus();
}
Upvotes: 3
Reputation: 939
If you just want to make autofocus in React, it's simple.
<input autoFocus type="text" />
While if you just want to know where to put that code, answer is in componentDidMount().
v014.3
componentDidMount() {
this.refs.linkInput.focus()
}
In most cases, you can attach a ref to the DOM node and avoid using findDOMNode at all.
Read the API documents here: https://facebook.github.io/react/docs/top-level-api.html#reactdom.finddomnode
Upvotes: 71
Reputation: 5450
Ref. @Dave's comment on @Dhiraj's answer; an alternative is to use the callback functionality of the ref attribute on the element being rendered (after a component first renders):
<input ref={ function(component){ React.findDOMNode(component).focus();} } />
Upvotes: 14
Reputation: 11370
This is not longer the best answer. As of v0.13, this.refs
may not available until AFTER componentDidMount()
runs, in some odd cases.
Just add the autoFocus
tag to your input field, as FakeRainBrigand showed above.
Upvotes: 16
Reputation: 1222
You can put that method call inside the render function. Or inside the life cycle method, componentDidUpdate
Upvotes: 9