diff --git a/packages/components/src/index.native.js b/packages/components/src/index.native.js
index 881b011c8a08a..5965c13e26eae 100644
--- a/packages/components/src/index.native.js
+++ b/packages/components/src/index.native.js
@@ -21,7 +21,8 @@ export { default as withSpokenMessages } from './higher-order/with-spoken-messag
// Mobile Components
export { default as BottomSheet } from './mobile/bottom-sheet';
-export { default as Picker } from './mobile/picker';
+export { default as HTMLTextInput } from './mobile/html-text-input';
export { default as KeyboardAvoidingView } from './mobile/keyboard-avoiding-view';
export { default as KeyboardAwareFlatList } from './mobile/keyboard-aware-flat-list';
+export { default as Picker } from './mobile/picker';
export { default as ReadableContentView } from './mobile/readable-content-view';
diff --git a/packages/components/src/mobile/html-text-input/container.android.js b/packages/components/src/mobile/html-text-input/container.android.js
new file mode 100644
index 0000000000000..ef62fc0178a3d
--- /dev/null
+++ b/packages/components/src/mobile/html-text-input/container.android.js
@@ -0,0 +1,22 @@
+/**
+ * External dependencies
+ */
+import { ScrollView } from 'react-native';
+
+/**
+ * Internal dependencies
+ */
+import KeyboardAvoidingView from '../keyboard-avoiding-view';
+import styles from './style.android.scss';
+
+const HTMLInputContainer = ( { children, parentHeight } ) => (
+
+
+ { children }
+
+
+);
+
+HTMLInputContainer.scrollEnabled = false;
+
+export default HTMLInputContainer;
diff --git a/packages/components/src/mobile/html-text-input/container.ios.js b/packages/components/src/mobile/html-text-input/container.ios.js
new file mode 100644
index 0000000000000..a9074311f473b
--- /dev/null
+++ b/packages/components/src/mobile/html-text-input/container.ios.js
@@ -0,0 +1,50 @@
+/**
+ * External dependencies
+ */
+import { UIManager, PanResponder } from 'react-native';
+
+/**
+ * WordPress dependencies
+ */
+import { Component } from '@wordpress/element';
+
+/**
+ * Internal dependencies
+ */
+import KeyboardAvoidingView from '../keyboard-avoiding-view';
+import styles from './style.ios.scss';
+
+class HTMLInputContainer extends Component {
+ constructor() {
+ super( ...arguments );
+
+ this.panResponder = PanResponder.create( {
+ onStartShouldSetPanResponderCapture: () => true,
+
+ onPanResponderMove: ( e, gestureState ) => {
+ if ( gestureState.dy > 100 && gestureState.dy < 110 ) {
+ //Keyboard.dismiss() and this.textInput.blur() are not working here
+ //They require to know the currentlyFocusedID under the hood but
+ //during this gesture there's no currentlyFocusedID
+ UIManager.blur( e.target );
+ }
+ },
+ } );
+ }
+
+ render() {
+ return (
+
+ { this.props.children }
+
+ );
+ }
+}
+
+HTMLInputContainer.scrollEnabled = true;
+
+export default HTMLInputContainer;
diff --git a/packages/components/src/mobile/html-text-input/index.native.js b/packages/components/src/mobile/html-text-input/index.native.js
new file mode 100644
index 0000000000000..3811085213dd1
--- /dev/null
+++ b/packages/components/src/mobile/html-text-input/index.native.js
@@ -0,0 +1,115 @@
+/**
+ * External dependencies
+ */
+import { TextInput } from 'react-native';
+
+/**
+ * WordPress dependencies
+ */
+import { Component } from '@wordpress/element';
+import { __ } from '@wordpress/i18n';
+import { parse } from '@wordpress/blocks';
+import { withDispatch, withSelect } from '@wordpress/data';
+import { withInstanceId, compose } from '@wordpress/compose';
+
+/**
+ * Internal dependencies
+ */
+import HTMLInputContainer from './container';
+import styles from './style.scss';
+
+export class HTMLTextInput extends Component {
+ constructor() {
+ super( ...arguments );
+
+ this.edit = this.edit.bind( this );
+ this.stopEditing = this.stopEditing.bind( this );
+
+ this.state = {
+ isDirty: false,
+ value: '',
+ };
+ }
+
+ static getDerivedStateFromProps( props, state ) {
+ if ( state.isDirty ) {
+ return null;
+ }
+
+ return {
+ value: props.value,
+ isDirty: false,
+ };
+ }
+
+ componentWillUnmount() {
+ //TODO: Blocking main thread
+ this.stopEditing();
+ }
+
+ edit( html ) {
+ this.props.onChange( html );
+ this.setState( { value: html, isDirty: true } );
+ }
+
+ stopEditing() {
+ if ( this.state.isDirty ) {
+ this.props.onPersist( this.state.value );
+ this.setState( { isDirty: false } );
+ }
+ }
+
+ render() {
+ return (
+
+
+
+
+ );
+ }
+}
+
+export default compose( [
+ withSelect( ( select ) => {
+ const {
+ getEditedPostContent,
+ } = select( 'core/editor' );
+
+ return {
+ value: getEditedPostContent(),
+ };
+ } ),
+ withDispatch( ( dispatch ) => {
+ const { resetBlocks } = dispatch( 'core/block-editor' );
+ const { editPost } = dispatch( 'core/editor' );
+ return {
+ onChange( content ) {
+ editPost( { content } );
+ },
+ onPersist( content ) {
+ resetBlocks( parse( content ) );
+ },
+ };
+ } ),
+ withInstanceId,
+] )( HTMLTextInput );
diff --git a/packages/components/src/mobile/html-text-input/style-common.native.scss b/packages/components/src/mobile/html-text-input/style-common.native.scss
new file mode 100644
index 0000000000000..4db5b98516140
--- /dev/null
+++ b/packages/components/src/mobile/html-text-input/style-common.native.scss
@@ -0,0 +1,15 @@
+$padding: 8;
+$backgroundColor: $white;
+$htmlFont: $default-monospace-font;
+
+.keyboardAvoidingView {
+ position: absolute;
+ top: 0;
+ right: 0;
+ left: 0;
+ bottom: 0;
+}
+
+.container {
+ flex: 1;
+}
diff --git a/packages/components/src/mobile/html-text-input/style.android.scss b/packages/components/src/mobile/html-text-input/style.android.scss
new file mode 100644
index 0000000000000..10594358722c3
--- /dev/null
+++ b/packages/components/src/mobile/html-text-input/style.android.scss
@@ -0,0 +1,23 @@
+@import "./style-common.scss";
+
+.htmlView {
+ font-family: $htmlFont;
+ background-color: $backgroundColor;
+ padding-left: $padding;
+ padding-right: $padding;
+ padding-top: $padding;
+ padding-bottom: $padding + 16;
+}
+
+.htmlViewTitle {
+ font-family: $htmlFont;
+ background-color: $backgroundColor;
+ padding-left: $padding;
+ padding-right: $padding;
+ padding-top: $padding;
+ padding-bottom: $padding;
+}
+
+.scrollView {
+ flex: 1;
+}
diff --git a/packages/components/src/mobile/html-text-input/style.ios.scss b/packages/components/src/mobile/html-text-input/style.ios.scss
new file mode 100644
index 0000000000000..8b13392b95a9a
--- /dev/null
+++ b/packages/components/src/mobile/html-text-input/style.ios.scss
@@ -0,0 +1,21 @@
+@import "./style-common.scss";
+
+$title-height: 32;
+
+.htmlView {
+ font-family: $htmlFont;
+ background-color: $backgroundColor;
+ padding-left: $padding;
+ padding-right: $padding;
+ padding-bottom: $title-height + $padding;
+}
+
+.htmlViewTitle {
+ font-family: $htmlFont;
+ background-color: $backgroundColor;
+ padding-left: $padding;
+ padding-right: $padding;
+ padding-top: $padding;
+ padding-bottom: $padding;
+ height: $title-height;
+}