diff --git a/docs/src/pages/component-api/MobileStepper/MobileStepper.md b/docs/src/pages/component-api/MobileStepper/MobileStepper.md
new file mode 100644
index 00000000000000..b4d5bc41432970
--- /dev/null
+++ b/docs/src/pages/component-api/MobileStepper/MobileStepper.md
@@ -0,0 +1,35 @@
+# MobileStepper
+
+
+
+## Props
+| Name | Type | Default | Description |
+|:-----|:-----|:--------|:------------|
+| activeStep | number | `0` | Specifies the currently active step. |
+| disableBack | bool | `false` | Set to disable the back button. |
+| disableNext | bool | `false` | Set to disable the next button. |
+| kind | `text`, `dots` or `progress` | `dots` | Defines the kind of mobile stepper to use. |
+| onBack | function | | Supplied to the onClick attribute of the back button. |
+| onNext | function | | Supplied to the onClick attribute of the next button. |
+| steps | number | | The total amount of steps. |
+
+
+Any other properties supplied will be spread to the root element.
+
+## Classes
+
+You can overrides all the class names injected by Material-UI thanks to the `classes` property.
+This property accepts the following keys:
+- `mobileStepper`
+- `button`
+- `dots`
+- `dot`
+- `dotActive`
+- `progressClassName`
+
+Have a look at [overriding with class names](/customization/overrides#overriding-with-class-names)
+section for more detail.
+
+If using the `overrides` key of the theme as documented
+[here](/customization/themes#customizing-all-instances-of-a-component-type),
+you need to use the following style sheet name: `MuiAppBar`.
diff --git a/docs/src/pages/component-demos/mobile-stepper/DotsMobileStepper.js b/docs/src/pages/component-demos/mobile-stepper/DotsMobileStepper.js
new file mode 100644
index 00000000000000..14a5befad60169
--- /dev/null
+++ b/docs/src/pages/component-demos/mobile-stepper/DotsMobileStepper.js
@@ -0,0 +1,64 @@
+// @flow
+
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import { withStyles, createStyleSheet } from 'material-ui/styles';
+import MobileStepper from 'material-ui/MobileStepper';
+
+const styleSheet = createStyleSheet('DotsMobileStepper', {
+ root: {
+ position: 'relative',
+ marginTop: 30,
+ width: '100%',
+ },
+ mobileStepper: {
+ position: 'relative',
+ },
+});
+
+class DotsMobileStepper extends Component {
+ static propTypes = {
+ classes: PropTypes.object.isRequired,
+ };
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ activeStep: 0,
+ };
+ }
+
+ handleOnNext = () => {
+ const activeStep = this.state.activeStep === 5 ? 5 : this.state.activeStep + 1;
+ this.setState({
+ activeStep,
+ });
+ };
+
+ handleOnBack = () => {
+ const activeStep = this.state.activeStep === 0 ? 0 : this.state.activeStep - 1;
+ this.setState({
+ activeStep,
+ });
+ };
+
+ render() {
+ const classes = this.props.classes;
+ return (
+
+
+
+ );
+ }
+}
+
+export default withStyles(styleSheet)(DotsMobileStepper);
diff --git a/docs/src/pages/component-demos/mobile-stepper/ProgressMobileStepper.js b/docs/src/pages/component-demos/mobile-stepper/ProgressMobileStepper.js
new file mode 100644
index 00000000000000..2d16897e4f0c44
--- /dev/null
+++ b/docs/src/pages/component-demos/mobile-stepper/ProgressMobileStepper.js
@@ -0,0 +1,64 @@
+// @flow
+
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import { withStyles, createStyleSheet } from 'material-ui/styles';
+import MobileStepper from 'material-ui/MobileStepper';
+
+const styleSheet = createStyleSheet('ProgressMobileStepper', {
+ root: {
+ position: 'relative',
+ marginTop: 30,
+ width: '100%',
+ },
+ mobileStepper: {
+ position: 'relative',
+ },
+});
+
+class ProgressMobileStepper extends Component {
+ static propTypes = {
+ classes: PropTypes.object.isRequired,
+ };
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ activeStep: 0,
+ };
+ }
+
+ handleOnNext = () => {
+ const activeStep = this.state.activeStep === 5 ? 5 : this.state.activeStep + 1;
+ this.setState({
+ activeStep,
+ });
+ };
+
+ handleOnBack = () => {
+ const activeStep = this.state.activeStep === 0 ? 0 : this.state.activeStep - 1;
+ this.setState({
+ activeStep,
+ });
+ };
+
+ render() {
+ const classes = this.props.classes;
+ return (
+
+
+
+ );
+ }
+}
+
+export default withStyles(styleSheet)(ProgressMobileStepper);
diff --git a/docs/src/pages/component-demos/mobile-stepper/TextMobileStepper.js b/docs/src/pages/component-demos/mobile-stepper/TextMobileStepper.js
new file mode 100644
index 00000000000000..b1c609f3b4cde0
--- /dev/null
+++ b/docs/src/pages/component-demos/mobile-stepper/TextMobileStepper.js
@@ -0,0 +1,81 @@
+// @flow
+
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import { withStyles, createStyleSheet } from 'material-ui/styles';
+import MobileStepper from 'material-ui/MobileStepper';
+import Paper from 'material-ui/Paper';
+
+const styleSheet = createStyleSheet('TextMobileStepper', {
+ root: {
+ position: 'relative',
+ marginTop: 30,
+ width: '100%',
+ },
+ mobileStepper: {
+ position: 'relative',
+ },
+ textualDescription: {
+ display: 'flex',
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ alignItems: 'center',
+ width: '100%',
+ position: 'relative',
+ height: '50px',
+ left: 0,
+ fontSize: '14px',
+ paddingLeft: '28px',
+ marginBottom: '20px',
+ },
+});
+
+class TextMobileStepper extends Component {
+ static propTypes = {
+ classes: PropTypes.object.isRequired,
+ };
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ activeStep: 0,
+ };
+ }
+
+ handleOnNext = () => {
+ const activeStep = this.state.activeStep === 5 ? 5 : this.state.activeStep + 1;
+ this.setState({
+ activeStep,
+ });
+ };
+
+ handleOnBack = () => {
+ const activeStep = this.state.activeStep === 0 ? 0 : this.state.activeStep - 1;
+ this.setState({
+ activeStep,
+ });
+ };
+
+ render() {
+ const classes = this.props.classes;
+ return (
+
+
+ Step {this.state.activeStep + 1} of 6
+
+
+
+ );
+ }
+}
+
+export default withStyles(styleSheet)(TextMobileStepper);
diff --git a/docs/src/pages/component-demos/mobile-stepper/mobile-stepper.md b/docs/src/pages/component-demos/mobile-stepper/mobile-stepper.md
new file mode 100644
index 00000000000000..1d3436262e5719
--- /dev/null
+++ b/docs/src/pages/component-demos/mobile-stepper/mobile-stepper.md
@@ -0,0 +1,22 @@
+---
+components: MobileStepper
+---
+
+# MobileStepper
+
+The [MobileStepper](https://material.io/guidelines/layout/structure.html#structure-mobile-stepper) implements a compact stepper suitable for a mobile device.
+
+## Mobile Stepper - Dots
+
+{{demo='pages/component-demos/mobile-stepper/DotsMobileStepper.js'}}
+
+## Mobile Stepper - Text
+
+This is essentially a back/next button positioned correctly. You must implement the textual description yourself however an example is provided below for reference.
+
+{{demo='pages/component-demos/mobile-stepper/TextMobileStepper.js'}}
+
+## Mobile Stepper - Progress
+
+{{demo='pages/component-demos/mobile-stepper/ProgressMobileStepper.js'}}
+
diff --git a/docs/src/pages/getting-started/supported-components.md b/docs/src/pages/getting-started/supported-components.md
index dc239579be2e2a..e25578f7f8b37f 100644
--- a/docs/src/pages/getting-started/supported-components.md
+++ b/docs/src/pages/getting-started/supported-components.md
@@ -96,6 +96,7 @@ to discuss the approach before submitting a PR.
- [Steppers](https://www.google.com/design/spec/components/steppers.html)
- [Horizontal](https://www.google.com/design/spec/components/steppers.html#steppers-types-of-steppers)
- [Vertical](https://www.google.com/design/spec/components/steppers.html#steppers-types-of-steppers)
+ - [MobileStepper](https://www.google.com/design/spec/components/mobile-stepper.html)
- **[Tabs](https://www.google.com/design/spec/components/tabs.html) ✓**
- Usage
- **[Mobile (Full width)](https://www.google.com/design/spec/components/tabs.html#tabs-usage) ✓**
diff --git a/src/MobileStepper/MobileStepper.js b/src/MobileStepper/MobileStepper.js
new file mode 100644
index 00000000000000..54e77b90c75702
--- /dev/null
+++ b/src/MobileStepper/MobileStepper.js
@@ -0,0 +1,165 @@
+// @flow weak
+
+import React from 'react';
+import PropTypes from 'prop-types';
+import classNames from 'classnames';
+import { createStyleSheet } from 'jss-theme-reactor';
+import withStyles from '../styles/withStyles';
+import Paper from '../Paper';
+import Button from '../Button';
+import KeyboardArrowLeft from '../svg-icons/keyboard-arrow-left';
+import KeyboardArrowRight from '../svg-icons/keyboard-arrow-right';
+import { LinearProgress } from '../Progress';
+
+export const styleSheet = createStyleSheet('MuiMobileStepper', theme => ({
+ mobileStepper: {
+ display: 'flex',
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ alignItems: 'center',
+ width: '100%',
+ position: 'fixed',
+ bottom: 0,
+ left: 0,
+ zIndex: theme.zIndex.mobileStepper,
+ backgroundColor: theme.palette.background.paper,
+ padding: '6px',
+ },
+ button: {},
+ dots: {
+ display: 'flex',
+ flexDirection: 'row',
+ },
+ dot: {
+ backgroundColor: theme.palette.action.disabled,
+ borderRadius: '50%',
+ width: '10px',
+ height: '10px',
+ margin: '0 2px',
+ },
+ dotActive: {
+ backgroundColor: theme.palette.primary[500],
+ },
+ progressClassName: {
+ width: '50%',
+ },
+}));
+
+function MobileStepper(props) {
+ const {
+ activeStep,
+ buttonClassName: buttonClassNameProp,
+ classes,
+ className: classNameProp,
+ disableBack,
+ disableNext,
+ dotClassName: dotClassNameProp,
+ dotsClassName: dotsClassNameProp,
+ kind,
+ onBack,
+ onNext,
+ progressClassName: progressClassNameProp,
+ steps,
+ ...other
+ } = props;
+
+ const className = classNames(classes.mobileStepper, classNameProp);
+ const dotsClassName = classNames(classes.dots, dotsClassNameProp);
+ const buttonClassName = classNames(classes.button, buttonClassNameProp);
+ const progressClassName = classNames(classes.progressClassName, progressClassNameProp);
+
+ return (
+
+
+ {kind === 'dots' &&
+
+ {Array.from(Array(steps)).map((_, step) => {
+ const dotClassName = classNames(
+ {
+ [classes.dot]: true,
+ [classes.dotActive]: step === activeStep,
+ },
+ dotClassNameProp,
+ );
+ return
; // eslint-disable-line react/no-array-index-key,max-len
+ })}
+
}
+ {kind === 'progress' &&
+
+
+
}
+
+
+ );
+}
+
+MobileStepper.propTypes = {
+ /**
+ * Set the active step (zero based index). This will enable `Step` control helpers.
+ */
+ activeStep: PropTypes.number,
+ /**
+ * @ignore
+ */
+ buttonClassName: PropTypes.string,
+ /**
+ * Useful to extend the style applied to components.
+ */
+ classes: PropTypes.object.isRequired,
+ /**
+ * @ignore
+ */
+ className: PropTypes.string,
+ /**
+ * Set to true to disable the back button.
+ */
+ disableBack: PropTypes.bool,
+ /**
+ * Set to true to disable the next button.
+ */
+ disableNext: PropTypes.bool,
+ /**
+ * @ignore
+ */
+ dotClassName: PropTypes.string,
+ /**
+ * @ignore
+ */
+ dotsClassName: PropTypes.string,
+ /**
+ * The kind of mobile stepper to use.
+ */
+ kind: PropTypes.oneOf(['text', 'dots', 'progress']),
+ /**
+ * Passed into the onTouchTap prop of the Back button.
+ */
+ onBack: PropTypes.func.isRequired,
+ /**
+ * Passed into the onTouchTap prop of the Next button.
+ */
+ onNext: PropTypes.func.isRequired,
+ /**
+ * @ignore
+ */
+ progressClassName: PropTypes.string,
+ /**
+ * The total steps.
+ */
+ steps: PropTypes.number.isRequired,
+};
+
+MobileStepper.defaultProps = {
+ activeStep: 0,
+ kind: 'dots',
+ disableBack: false,
+ disableNext: false,
+};
+
+export default withStyles(styleSheet)(MobileStepper);
diff --git a/src/MobileStepper/MobileStepper.spec.js b/src/MobileStepper/MobileStepper.spec.js
new file mode 100644
index 00000000000000..b5e896cb8e6bbf
--- /dev/null
+++ b/src/MobileStepper/MobileStepper.spec.js
@@ -0,0 +1,138 @@
+// @flow
+
+import React from 'react';
+import { assert } from 'chai';
+import { createShallow } from '../test-utils';
+import MobileStepper, { styleSheet } from './MobileStepper';
+import Button from '../Button/Button';
+import KeyboardArrowLeft from '../svg-icons/keyboard-arrow-left';
+import KeyboardArrowRight from '../svg-icons/keyboard-arrow-right';
+import { LinearProgress } from '../Progress';
+
+describe('', () => {
+ let shallow;
+ let classes;
+ const defaultProps = {
+ steps: 2,
+ onBack: () => {},
+ onNext: () => {},
+ };
+
+ before(() => {
+ shallow = createShallow({ dive: true });
+ classes = shallow.context.styleManager.render(styleSheet);
+ });
+
+ it('should render a Paper component', () => {
+ const wrapper = shallow();
+ assert.strictEqual(wrapper.name(), 'withStyles(Paper)');
+ assert.strictEqual(wrapper.props().elevation, 0, 'should have no elevation');
+ });
+ it('should render with the mobileStepper class', () => {
+ const wrapper = shallow();
+ assert.strictEqual(
+ wrapper.hasClass(classes.mobileStepper),
+ true,
+ 'should have the mobileStepper class',
+ );
+ });
+ it('should render the custom className and the mobileStepper class', () => {
+ const wrapper = shallow();
+ assert.strictEqual(wrapper.is('.test-class-name'), true, 'should pass the test className');
+ assert.strictEqual(
+ wrapper.hasClass(classes.mobileStepper),
+ true,
+ 'should have the mobileStepper class',
+ );
+ });
+ it('should render two buttons', () => {
+ const wrapper = shallow();
+ assert.lengthOf(wrapper.find(Button), 2, 'should render two buttons');
+ });
+ it('should render a as the 1st child with a component', () => {
+ const wrapper = shallow();
+ const backButton = wrapper.childAt(0);
+ assert.lengthOf(
+ backButton.find(KeyboardArrowLeft),
+ 1,
+ 'should render a single component',
+ );
+ });
+ it('should render a as the 3rd child with a component', () => {
+ const wrapper = shallow();
+ const nextButton = wrapper.childAt(2);
+ assert.lengthOf(
+ nextButton.find(KeyboardArrowRight),
+ 1,
+ 'should render a single component',
+ );
+ });
+ it('should disable the back button if prop disableBack is passed', () => {
+ const wrapper = shallow();
+ const backButton = wrapper.childAt(0);
+ assert.strictEqual(backButton.prop('disabled'), true, 'should disable the back button');
+ });
+ it('should disable the next button if prop disableNext is passed', () => {
+ const wrapper = shallow();
+ const nextButton = wrapper.childAt(2);
+ assert.strictEqual(nextButton.prop('disabled'), true, 'should disable the next button');
+ });
+ it('should render just two buttons when supplied with kind text', () => {
+ const wrapper = shallow();
+ assert.lengthOf(wrapper.children(), 2, 'should render exactly two children');
+ });
+ it('should render dots when supplied with kind dots', () => {
+ const wrapper = shallow();
+ assert.lengthOf(wrapper.children(), 3, 'should render exactly three children');
+ assert.strictEqual(
+ wrapper.childAt(1).hasClass(classes.dots),
+ true,
+ 'should have a single dots class',
+ );
+ });
+ it('should render a dot for each step when using dots kind', () => {
+ const wrapper = shallow();
+ assert.lengthOf(wrapper.find(`.${classes.dot}`), 2, 'should render exactly two dots');
+ });
+ it('should render the first dot as active if activeStep is not set', () => {
+ const wrapper = shallow();
+ assert.strictEqual(
+ wrapper.childAt(1).childAt(0).hasClass(classes.dotActive),
+ true,
+ 'should render the first dot active',
+ );
+ });
+ it('should honour the activeStep prop', () => {
+ const wrapper = shallow();
+ assert.strictEqual(
+ wrapper.childAt(1).childAt(1).hasClass(classes.dotActive),
+ true,
+ 'should render the second dot active',
+ );
+ });
+ it('should render a when supplied with kind progress', () => {
+ const wrapper = shallow();
+ assert.lengthOf(wrapper.find(LinearProgress), 1, 'should render a ');
+ });
+ it('should calculate the value correctly', () => {
+ const props = {
+ onBack: defaultProps.onBack,
+ onNext: defaultProps.onNext,
+ };
+ let wrapper = shallow();
+ let linearProgressProps = wrapper.find(LinearProgress).props();
+ assert.strictEqual(linearProgressProps.value, 0, 'should set value to 0');
+
+ wrapper = shallow();
+ linearProgressProps = wrapper.find(LinearProgress).props();
+ assert.strictEqual(linearProgressProps.value, 50, 'should set value to 50');
+
+ wrapper = shallow();
+ linearProgressProps = wrapper.find(LinearProgress).props();
+ assert.strictEqual(
+ linearProgressProps.value,
+ 100,
+ 'should set value to 100',
+ );
+ });
+});
diff --git a/src/MobileStepper/index.js b/src/MobileStepper/index.js
new file mode 100644
index 00000000000000..dbd564de92a83f
--- /dev/null
+++ b/src/MobileStepper/index.js
@@ -0,0 +1,3 @@
+// @flow
+
+export { default } from './MobileStepper';
diff --git a/src/styles/muiThemeProviderFactory.js b/src/styles/muiThemeProviderFactory.js
index da9980e8bea1a0..c0ae1314af11bb 100644
--- a/src/styles/muiThemeProviderFactory.js
+++ b/src/styles/muiThemeProviderFactory.js
@@ -96,6 +96,8 @@ export const MUI_SHEET_ORDER = [
'MuiToolbar',
'MuiBadge',
+
+ 'MuiMobileStepper',
];
export default function muiThemeProviderFactory(defaultTheme) {
diff --git a/src/styles/zIndex.js b/src/styles/zIndex.js
index f522efbb7ad5b2..5e1ae4bc8932ff 100644
--- a/src/styles/zIndex.js
+++ b/src/styles/zIndex.js
@@ -12,4 +12,5 @@ export default {
popover: 2100,
snackbar: 2900,
tooltip: 3000,
+ mobileStepper: 1100,
};