21

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
  • 31,161
  • 42
  • 171
  • 354
ReganPerkins
  • 1,605
  • 3
  • 16
  • 36

6 Answers6

44

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,199
  • 15
  • 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
  • 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
4

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
  • 14,473
  • 5
  • 42
  • 52
  • 1
    **TIP:** No need for `length` *const*, you can do `input.setSelectionRange(Infinity, Infinity)` – vsync Jun 17 '20 at 12:25
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,081
  • 3
  • 30
  • 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} />;
}
0

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
  • 950
  • 8
  • 16
-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,559
  • 1
  • 11
  • 25