23

I have a controlled input that has a value initially showing. I have set that input to autoFocus but the cursor appears at the beginning of the input when I am wanting it to appear at the end. I understand this might be because the autoFocus is added before the value is but I'm not 100% sure.

What would be the best way to accomplish the cursor initializing at the end of the input field?

var Test = React.createClass({

    getInitialState: function() {
        return {
           teamId: 'fdsfds'
        };
    },

    render: function() {
        return (
                <input type="text" autoFocus value={this.state.teamId} onChange={this.setTeamId} />
        );
    },

    setTeamId: function(event) {
        this.setState({ teamId: id });
    },

});

ReactDOM.render(
  <Test />,
  document.getElementById('container')
);

https://jsfiddle.net/69z2wepo/34486/

Can Poyrazoğlu
  • 33,241
  • 48
  • 191
  • 389
ReganPerkins
  • 1,645
  • 3
  • 17
  • 36

6 Answers6

45

One solution:

<input
  type="text"
  autoFocus
  value={this.state.teamId}
  onChange={this.setTeamId}
  onFocus={function(e) {
    var val = e.target.value;
    e.target.value = '';
    e.target.value = val;
  }}
/>

https://jsfiddle.net/o3s05zz4/1/

Adaptation of this answer: https://stackoverflow.com/a/2345915/1589521

Ted A.
  • 2,264
  • 17
  • 22
  • Perhaps extract the logic out in another method as is the case with other props? Works perfectly fine, btw. – GopherGopher Aug 21 '20 at 02:30
  • 1
    This doesn't seem to be a good solution because it moves the cursor at the end not just for the auto focus but also when user focuses the input by clicking into it later. Not good UX. – Jakub Kotrs Feb 02 '21 at 13:07
  • 1
    I just incremented the likes from 42 to 43. Maybe I should have left it at 42. – davidkuda Mar 10 '22 at 21:50
7

This actually works:

componentDidMount() {
    const input = this.input;
    const length = input.value.length;
    input.focus();
    input.setSelectionRange(length, length);
}

render() {
   return (
       <input ref={ref => this.input = ref} ... >
   )
}

PS. If you need to support IE8 and below you'll need to use IE-specific checks.

Spadar Shut
  • 15,111
  • 5
  • 47
  • 54
  • 1
    **TIP:** No need for `length` *const*, you can do `input.setSelectionRange(Infinity, Infinity)` – vsync Jun 17 '20 at 12:25
  • @vsync your tip did not work for me - the caret was placed at the beginning. Had to specify length as in the answer. – Magnus Teekivi Nov 05 '22 at 16:08
1

This way the text of the input will be selected, ready to edit

<input
  type="text"
  defaultValue="Untitled"
  autoFocus
  onFocus={e => e.currentTarget.select()}
/>
Ale DC
  • 1,646
  • 13
  • 20
0

Setting the input value inside componentDidMount seems to do the trick, but it feels like a hack:

componentDidMount: function(){
    this.inputElement.value = this.state.teamId;
},

render: function() {
    var that = this;
    return <input ref={function(ref){that.inputElement = ref;}} type="text" autoFocus value={this.state.teamId} onChange={this.setTeamId} />;
},

https://jsfiddle.net/yuk13tuu/

dannyjolie
  • 10,959
  • 3
  • 33
  • 28
0

In TypeScript:

private inputDOM: HTMLInputElement | null;

public componentDidMount() {
    if (this.inputDOM != null) {
        this.inputDOM.value = '';
        this.inputDOM.value = this.state.newRegionName;
    }
}

public render() {
    return <input ref={(ref: HTMLInputElement | null) => this.inputDOM = ref} type="text" autoFocus={true} value={this.state.inputValue} />;
}
-1

Looks like the html attribute autofocus doesn't take any parameters to specify where the cursor should start. See mdn documentation.

Sitepoint has a great tutorial explaining your options for setting cursor position from within an input box.

As for the reacty side of things, you'll simply put your jQuery (or other cursor related code) in the componentDidMount lifecycle method.

thealexbaron
  • 1,558
  • 1
  • 11
  • 25