JSFiddle - React, Tailwind, and code Playground

by Jason Miller

HTML

<script src="https://unpkg.com/preact"></script>

CSS

div[contentEditable] {
  min-height: 50px;
  padding: 10px;
  background: white;
  border: 1px solid #CCC;
  border-radius: 3px;
}

Babel + JSX

const { h, Component, render } = preact; /** @jsx h */

class Demo extends Component {
	state = { content: '' };
  // when pressing enter, insert an HR
  onChange = ({ value, keyCode }) => {
		let content = value;
		if (keyCode===13) {
			content = this.state.content + '<hr>';
    }
		this.setState({ content });
  };
	render({}, { content }) {
		return (
			<Editor
				value={content}
				onChange={this.onChange}
			/>
		);
	}
}

/** It's ideal to wrap in a sCU */
class Editor extends Component {
	shouldComponentUpdate(nextProps) {
		return nextProps.value!==this.props.value && nextProps.value!==this.currentValue;
	}
	handleKeyDown = e => {
		let value = this.base.innerHTML;
		this.currentValue = value;
		let evt = { value, keyCode: e.keyCode };
		if (this.props.onChange(evt)===false) {
			return e.preventDefault(), false;
		}
	};
	moveSelectionToEnd = () => {
		let sel = getSelection();
		sel.removeAllRanges();
		let range = document.createRange();
		range.setStartAfter(this.base.lastChild);
		sel.addRange(range);
	};
	componentDidUpdate(prevProps) {
		let { value } = this.props;
		if (value.length > prevProps.value.length) {
			this.moveSelectionToEnd();
		}
	}
	render({ value }) {
		return (
      <div
        contentEditable
        onKeyDown={this.handleKeyDown}
        dangerouslySetInnerHTML={{
          __html: value
        }}
      />
		);
	}
}

render(<Demo />, document.body);