javascriptdomcontenteditablereactjs

React.js: onChange event for contentEditable


How do I listen to change events for a contentEditable-based control?

function Number() {
  let [value, setValue] = useState('123');
  
  function onChange(v) {
    // Doesn't fire :(
    console.log('changed', v);
    setValue(v);
  }
  return <div>
    <span contentEditable={true} onChange={onChange}>
      {value}
    </span>
    =
    {value}
  </div>;
}

Code on Codepen.


Solution

  • See Sebastien Lorber's answer which fixes a bug in my implementation.


    Use the onInput event, and optionally onBlur as a fallback. You might want to save the previous contents to prevent sending extra events.

    I'd personally have this as my render function.

    var handleChange = function(event){
        this.setState({html: event.target.value});
    }.bind(this);
    
    return (<ContentEditable html={this.state.html} onChange={handleChange} />);
    

    jsbin

    Which uses this simple wrapper around contentEditable.

    var ContentEditable = React.createClass({
        render: function(){
            return <div
                onInput={this.emitChange}
                onBlur={this.emitChange}
                contentEditable
                dangerouslySetInnerHTML={{__html: this.props.html}}></div>;
        },
        shouldComponentUpdate: function(nextProps){
            return nextProps.html !== this.getDOMNode().innerHTML;
        },
        emitChange: function(){
            var html = this.getDOMNode().innerHTML;
            if (this.props.onChange && html !== this.lastHtml) {
    
                this.props.onChange({
                    target: {
                        value: html
                    }
                });
            }
            this.lastHtml = html;
        }
    });