Material-ui: [TextField] Cursor jumps to end of input on first edit when placed in a Dialog

Created on 5 Jun 2016  路  21Comments  路  Source: mui-org/material-ui

Problem description

All the TextFields in my app move the cursor to the end of the input on first edit. Subsequent edits work just fine.

Steps to reproduce

  1. Create a controlled TextField with some initial contents.
  2. Add a character in the middle of the initial contents
  3. Observe the cursor jumping to the end of the input

If I replace the <TextField .../> with an <input .../>, the behavior stops.

Versions

  • Material-UI: v0.15
  • React: v15.0.2
  • Browser: Several Firefox and Chrome

    Fix?

There is a hacky fix to the problem I'm observing - Comment out this line https://github.com/callemall/material-ui/blob/master/src/TextField/TextField.js#L356

this.setState({hasValue: isValid(event.target.value), isClean: false});

Then the problem goes away, although I'm sure this isn't a correct fix.

bug 馃悰 TextField

Most helpful comment

This is still an issue

All 21 comments

@joewalker I just tried using the controlled example in the docs, and it's working fine.

Here's my hunch as to what's up:

My TextField is in a Dialog, and it looks like Dialog works by having a second render loop, which I think means that setState might become asynchronous? If that's true, then maybe the answer is in here?

https://stackoverflow.com/questions/28922275/in-reactjs-why-does-setstate-behave-differently-when-called-synchronously/28922465#28922465

Quick video of what's going wrong:

screen recording 2016-06-05 at 10 22 pm

I press 'u' at the start of the TextField and the cursor jumps to the end.

Is there any documentation to what hasValue and isClean do?
I'm happy to work out a more correct fix

I'm afraid you may have to reverse engineer it to figure that out.

I'm experiencing the same issue with the same version. I'm observing that It's always jumps to the end if I do custom modification to the value each time a key is pressed. In my TextField I automatically add space between group of numbers to make it more readable. Do you have some kind of advice?

After some more research, It turn out my issue related to how react behave https://github.com/facebook/react/issues/955

@joewalker: I have replicated this issue in a dialog - it is a bit annoying!

This repros only for TextField in Dialog.

Use "defaultValue" instead of "value" with TextField will fix it.

Use "defaultValue" instead of "value" with TextField will fix it.

Right, except that this makes the TextField no longer be controlled, so it's not a fix to the problem.

It is controlled. Try it.

     <Dialog
          title="Add Item"
          modal={false}
          open={this.state.showDialog}
          >
            <TextField
              id="text-field-controlled"
              defaultValue={self.state.value}
              onChange={(e)=>{
                self.setState({
                  value: e.target.value
                })
              }}
            />
     </Dialog>

onChange will be triggered.

I am also having the same issue in all TextInputs. The temporary fix doesnt work. Is there any other work around?

It seems there are 2 ways of doing dialogs - with a portal so the dialog renders in a separate render loop, and without so the rendering is as you would expect.

The portal method probably makes for better webcompat, but it makes it harder to test with things like enzyme and causes problems like this.

My intention when I next visit this problem is to look at Boron and Skylight to see if they fit. They seem to not use portals and I'm hoping that it will make it easier to write unit tests.

I think we can close this since it appears to be an issue with React itself (https://github.com/facebook/react/issues/955#issuecomment-33104589).

cc @oliviertassinari.

Look for these code in TextField.js and comment out the line

// _this.setState({ hasValue: isValid(event.target.value), isClean: false });

This fixed the issue for me. It has been a while ago, I don't remember how I figure it out. Just want to share the code.

return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_Object$getPrototypeO = Object.getPrototypeOf(TextField)).call.apply(_Object$getPrototypeO, [this].concat(args))), _this), _this.state = {
  isFocused: false,
  errorText: undefined,
  hasValue: false,
  isClean: true
}, _this.handleInputBlur = function (event) {
  _this.setState({ isFocused: false });
  if (_this.props.onBlur) _this.props.onBlur(event);
}, _this.handleInputChange = function (event) {
  // _this.setState({ hasValue: isValid(event.target.value), isClean: false });
  if (_this.props.onChange) _this.props.onChange(event, event.target.value);
}, _this.handleInputFocus = function (event) {
  if (_this.props.disabled) return;
  _this.setState({ isFocused: true });
  if (_this.props.onFocus) _this.props.onFocus(event);
}, _this.handleInputKeyDown = function (event) {
  if ((0, _keycode2.default)(event) === 'enter' && _this.props.onEnterKeyDown) _this.props.onEnterKeyDown(event);
  if (_this.props.onKeyDown) _this.props.onKeyDown(event);
}, _this.handleHeightChange = function (event, height) {
  var newHeight = height + 24;
  if (_this.props.floatingLabelText) {
    newHeight += 24;
  }
  _reactDom2.default.findDOMNode(_this).style.height = newHeight + 'px';
}, _temp), _possibleConstructorReturn(_this, _ret);

}

@lucasbento Given the potential work-arounds in this thread and the linked React bug, I don't think it's a bug on their part. FWIW, the React team closed it as not a bug on their end. This seems very related to how a Dialog renders its children.

I haven't dove too deep, but I don't think the above solution is the right one. I'll post if I figure out anything more sustainable.

I'm having a slightly different problem that might be related to this. The cursor jumps to the end in a multiLine TextField on line break, only when the input is controlled and within a Dialog.

Multi-line TextField within Dialog (cursor jumps to the end):
out1

Multi-line TextField (works fine):
out2

My workaround was to make only this TextField uncontrolled for now.

My workaround was to not use a Dialog :(

This is still an issue

I'm also having the same issue on a controlled TextField.
It is not in a dialog. It's simply controls a phone input.

I'm using a workaround to fix the position manually on the next cycle. It's not the best fix, as the cursor blinks at the end and then returns to correct position.

setTimeout(fixCursorPosition, 0, event.currentTarget, formattedValue)

The workaround found in this comment fixed any instances of issues I was having. I'm not sure if it's safe enough to use within MUI's TextField directly though.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

chris-hinds picture chris-hinds  路  3Comments

FranBran picture FranBran  路  3Comments

ghost picture ghost  路  3Comments

newoga picture newoga  路  3Comments

mattmiddlesworth picture mattmiddlesworth  路  3Comments