redochka
redochka

Reputation: 12819

How to keep cursor position in a react input element

The cursor keeps going to the end. How to keep the cursor position when editing from the the middle of the string?

enter image description here

Code that I am using is:

const rootElement = document.getElementById('root');

class MyFancyForm extends React.Component {

    constructor(props) {
        super(props);
        this.state = {myValue: ""};
    }

    handleCommaSeparatedChange = event => {
        const {value} = event.target;
        this.setState({myValue: value});
    };




    render() {
        return(
            <form >

                <div>
                    <label>
                        Cursor position looser
                        <br />
                        <input onChange={this.handleCommaSeparatedChange} value={this.state.myValue} />
                    </label>
                </div>


            </form>
        )
    }
}

const element = <MyFancyForm />;

ReactDOM.render(element, rootElement);

Any idea how could I achieve it?

Upvotes: 29

Views: 20480

Answers (3)

Lewy Blue
Lewy Blue

Reputation: 618

I solved this by creating a TextInput component that wraps <input type="text"> and proxying the value in internal state.

function TextInput({ value, onChange }) {
    // Create a proxy value in internal state to prevent the caret from jumping to the end every time the value updates
    const [currentValue, setCurrentValue] = useState<string>(value);

    useEffect(() => {
        setCurrentValue(value);
    }, [value]);

    return (<input
                type="text"
                value={currentValue}
                onChange={(e) => {
                    setCurrentValue(e.target.value);

                    onChange(e.target.value);
                }}
            />);
}

Then I use it in a parent component like so. It works well so far.

<TextInput                  
    value={textValue}
    onChange={(e) => {
        setTextValue(e);
    }}
/>

Upvotes: 4

ius
ius

Reputation: 1599

I know it's an old post but this might help someone.

I found this snippet in one github issue and helped me to get around this problem.

onChange={(event) => {
  event.persist()
  const caretStart = event.target.selectionStart;
  const caretEnd = event.target.selectionEnd;
  // update the state and reset the caret
  this.updateState();
  event.target.setSelectionRange(caretStart, caretEnd);
}}

Quote from: https://github.com/facebook/react/issues/955#issuecomment-469344232

Upvotes: 3

Waseem Raja Shaik
Waseem Raja Shaik

Reputation: 343

just change value into defaultValue - it worked both in codepen and codesandbox for me

class MyFancyForm extends React.Component {

    constructor(props) {
        super(props);
        this.state = {myValue: ""};
    }

    handleCommaSeparatedChange = event => {
        const {value} = event.target;
        this.setState({myValue: value});
    };




    render() {
        return(
            <form >

                <div>
                    <label>
                        Cursor position looser
                        <br />
                        <input onChange={this.handleCommaSeparatedChange} defaultValue={this.state.myValue} />
                    </label>
                </div>


            </form>
        )
    }
}


  ReactDOM.render(
    <MyFancyForm />,
    document.getElementById('root')
  );

Upvotes: 16

Related Questions