diff --git a/packages/components/src/mobile/bottom-sheet/index.native.js b/packages/components/src/mobile/bottom-sheet/index.native.js
index 4de3335189dce..34d05a8397495 100644
--- a/packages/components/src/mobile/bottom-sheet/index.native.js
+++ b/packages/components/src/mobile/bottom-sheet/index.native.js
@@ -19,6 +19,7 @@ import Button from './button';
import Cell from './cell';
import PickerCell from './picker-cell';
import SwitchCell from './switch-cell';
+import RangeCell from './range-cell';
import KeyboardAvoidingView from './keyboard-avoiding-view';
class BottomSheet extends Component {
@@ -173,5 +174,6 @@ ThemedBottomSheet.Button = Button;
ThemedBottomSheet.Cell = Cell;
ThemedBottomSheet.PickerCell = PickerCell;
ThemedBottomSheet.SwitchCell = SwitchCell;
+ThemedBottomSheet.RangeCell = RangeCell;
export default ThemedBottomSheet;
diff --git a/packages/components/src/mobile/bottom-sheet/range-cell.native.js b/packages/components/src/mobile/bottom-sheet/range-cell.native.js
new file mode 100644
index 0000000000000..07b343e9ec078
--- /dev/null
+++ b/packages/components/src/mobile/bottom-sheet/range-cell.native.js
@@ -0,0 +1,46 @@
+/**
+ * External dependencies
+ */
+import { Platform } from 'react-native';
+
+/**
+ * Internal dependencies
+ */
+import Cell from './cell';
+import Slider from '../slider';
+
+export default function BottomSheetRangeCell( props ) {
+ const {
+ value,
+ defaultValue,
+ onChangeValue,
+ minimumValue = 0,
+ maximumValue = 10,
+ disabled,
+ step = 1,
+ minimumTrackTintColor = '#00669b',
+ maximumTrackTintColor = Platform.OS === 'ios' ? '#e9eff3' : '#909090',
+ thumbTintColor = Platform.OS === 'ios' ? '#fff' : '#00669b',
+ ...cellProps
+ } = props;
+
+ return (
+
+
+ |
+ );
+}
diff --git a/packages/components/src/mobile/slider/index.native.js b/packages/components/src/mobile/slider/index.native.js
new file mode 100644
index 0000000000000..111d9987e973d
--- /dev/null
+++ b/packages/components/src/mobile/slider/index.native.js
@@ -0,0 +1,118 @@
+/**
+ * External dependencies
+ */
+import { Slider as RNSlider, TextInput, View } from 'react-native';
+
+/**
+ * WordPress dependencies
+ */
+import { Component } from '@wordpress/element';
+
+/**
+ * Internal dependencies
+ */
+import styles from './styles.scss';
+
+class Slider extends Component {
+ constructor( props ) {
+ super( props );
+ this.handleToggleFocus = this.handleToggleFocus.bind( this );
+ this.handleChange = this.handleChange.bind( this );
+ this.handleValueSave = this.handleValueSave.bind( this );
+ this.handleReset = this.handleReset.bind( this );
+
+ const initialValue = this.validateInput( props.value || props.defaultValue || props.minimumValue );
+
+ this.state = { hasFocus: false, initialValue, sliderValue: initialValue };
+ }
+
+ componentDidUpdate( ) {
+ const reset = this.props.value === null;
+ if ( reset ) {
+ this.handleReset();
+ }
+ }
+
+ handleToggleFocus( validateInput = true ) {
+ const newState = { hasFocus: ! this.state.hasFocus };
+
+ if ( validateInput ) {
+ const sliderValue = this.validateInput( this.state.sliderValue );
+ this.handleValueSave( sliderValue );
+ }
+
+ this.setState( newState );
+ }
+
+ validateInput( text ) {
+ const { minimumValue, maximumValue } = this.props;
+ if ( ! text ) {
+ return minimumValue;
+ }
+ if ( typeof text === 'number' ) {
+ return Math.min( Math.max( text, minimumValue ), maximumValue );
+ }
+ return Math.min( Math.max( text.replace( /[^0-9]/g, '' ).replace( /^0+(?=\d)/, '' ), minimumValue ), maximumValue );
+ }
+
+ handleChange( text ) {
+ if ( ! isNaN( Number( text ) ) ) {
+ this.setState( { sliderValue: text } );
+ }
+ }
+
+ handleValueSave( text ) {
+ if ( ! isNaN( Number( text ) ) ) {
+ if ( this.props.onChangeValue ) {
+ this.props.onChangeValue( text );
+ }
+ this.setState( { sliderValue: text } );
+ }
+ }
+
+ handleReset() {
+ this.handleValueSave( this.props.defaultValue || this.state.initialValue );
+ }
+
+ render() {
+ const {
+ minimumValue,
+ maximumValue,
+ disabled,
+ step,
+ minimumTrackTintColor,
+ maximumTrackTintColor,
+ thumbTintColor,
+ } = this.props;
+
+ const { hasFocus, sliderValue } = this.state;
+
+ return (
+
+
+
+
+ );
+ }
+}
+
+export default Slider;
diff --git a/packages/components/src/mobile/slider/styles.scss b/packages/components/src/mobile/slider/styles.scss
new file mode 100644
index 0000000000000..326880b621807
--- /dev/null
+++ b/packages/components/src/mobile/slider/styles.scss
@@ -0,0 +1,27 @@
+.sliderContainer {
+ flex: 1;
+ flex-direction: row;
+ align-content: center;
+ justify-content: space-evenly;
+}
+
+.slider {
+ flex-grow: 1;
+}
+
+.sliderTextInput {
+ width: 40px;
+ height: 25px;
+ align-self: center;
+ margin-left: 10px;
+ border-width: 1px;
+ border-radius: 4px;
+ border-color: $dark-gray-150;
+ padding-top: 0;
+ padding-bottom: 0;
+}
+
+.isSelected {
+ border-width: 2px;
+ border-color: $blue-wordpress;
+}