diff --git a/e2e/components/stepper-e2e.spec.ts b/e2e/components/stepper-e2e.spec.ts
new file mode 100644
index 00000000000..cd9b4b3d821
--- /dev/null
+++ b/e2e/components/stepper-e2e.spec.ts
@@ -0,0 +1,84 @@
+import {
+ browser, by, element, ElementFinder, ExpectedConditions
+} from 'protractor';
+import {expectFocusOn, expectToExist} from '../util/asserts';
+import {pressKeys} from '../util/actions';
+import {Key} from 'selenium-webdriver';
+import {screenshot} from '../screenshot';
+
+describe('stepper', () => {
+ beforeEach(() => browser.get('/stepper'));
+
+ it('should render a stepper', () => {
+ expectToExist('md-horizontal-stepper');
+ screenshot('md-horizontal-stepper');
+ });
+
+ describe('basic behavior', () => {
+ it('should change steps correctly when stepper button is clicked', async () => {
+ const previousButton = element.all(by.buttonText('Back'));
+ const nextButton = element.all(by.buttonText('Next'));
+
+ expect(element(by.css('md-step-header[aria-selected="true"]')).getText())
+ .toBe('1\nFill out your name');
+
+ screenshot('start');
+ nextButton.get(0).click();
+
+ expect(element(by.css('md-step-header[aria-selected="true"]')).getText())
+ .toBe('2\nFill out your address');
+
+ await browser.wait(ExpectedConditions.not(
+ ExpectedConditions.presenceOf(element(by.css('div.mat-ripple-element')))));
+ screenshot('click next');
+
+ previousButton.get(0).click();
+
+ expect(element(by.css('md-step-header[aria-selected="true"]')).getText())
+ .toBe('1\nFill out your name');
+
+ await browser.wait(ExpectedConditions.not(
+ ExpectedConditions.presenceOf(element(by.css('div.mat-ripple-element')))));
+ screenshot('click back');
+ });
+
+ it('should change focus with keyboard interaction', () => {
+ let stepHeaders = element.all(by.css('md-step-header'));
+ stepHeaders.get(0).click();
+
+ expectFocusOn(stepHeaders.get(0));
+
+ pressKeys(Key.RIGHT);
+ expectFocusOn(stepHeaders.get(1));
+
+ pressKeys(Key.RIGHT);
+ expectFocusOn(stepHeaders.get(2));
+
+ pressKeys(Key.RIGHT);
+ expectFocusOn(stepHeaders.get(0));
+
+ pressKeys(Key.LEFT);
+ expectFocusOn(stepHeaders.get(2));
+
+ pressKeys(Key.SPACE, Key.ENTER);
+ expectFocusOn(stepHeaders.get(2));
+ });
+ });
+
+ describe('linear stepper', () => {
+ let linearButton: ElementFinder;
+
+ beforeEach(() => {
+ linearButton = element(by.id('toggle-linear'));
+ linearButton.click();
+ });
+
+ it('should not move to next step when stepper button is clicked', () => {
+ let nextButton = element.all(by.buttonText('Next'));
+ nextButton.get(0).click();
+
+ expect(element(by.css('md-step-header[aria-selected="true"]')).getText())
+ .toBe('1\nFill out your name');
+ });
+ });
+});
diff --git a/src/e2e-app/e2e-app-module.ts b/src/e2e-app/e2e-app-module.ts
index 8367ba4b7d3..e80b8c0a781 100644
--- a/src/e2e-app/e2e-app-module.ts
+++ b/src/e2e-app/e2e-app-module.ts
@@ -35,10 +35,12 @@ import {
MdRadioModule,
MdSidenavModule,
MdSlideToggleModule,
+ MdStepperModule,
MdTabsModule,
} from '@angular/material';
import {FullscreenOverlayContainer, OverlayContainer} from '@angular/cdk/overlay';
import {ExampleModule} from '@angular/material-examples';
+import {ReactiveFormsModule} from '@angular/forms';
/**
* NgModule that contains all Material modules that are required to serve the e2e-app.
@@ -59,6 +61,7 @@ import {ExampleModule} from '@angular/material-examples';
MdRadioModule,
MdSidenavModule,
MdSlideToggleModule,
+ MdStepperModule,
MdTabsModule,
MdNativeDateModule,
]
@@ -72,6 +75,7 @@ export class E2eMaterialModule {}
E2eMaterialModule,
NoopAnimationsModule,
ExampleModule,
+ ReactiveFormsModule
],
declarations: [
BasicTabs,
diff --git a/src/e2e-app/e2e-app/e2e-app.html b/src/e2e-app/e2e-app/e2e-app.html
index f21e4302024..e3631595618 100644
--- a/src/e2e-app/e2e-app/e2e-app.html
+++ b/src/e2e-app/e2e-app/e2e-app.html
@@ -18,6 +18,7 @@
Radios
Sidenav
Slide Toggle
+ Stepper
Tabs
Cards
Toolbar
diff --git a/src/e2e-app/e2e-app/routes.ts b/src/e2e-app/e2e-app/routes.ts
index 938564eccdc..db20eb23404 100644
--- a/src/e2e-app/e2e-app/routes.ts
+++ b/src/e2e-app/e2e-app/routes.ts
@@ -20,7 +20,8 @@ import {
ListOverviewExample,
ToolbarMultirowExample,
ButtonToggleOverviewExample,
- ExpansionOverviewExample
+ ExpansionOverviewExample,
+ StepperOverviewExample
} from '@angular/material-examples';
export const E2E_APP_ROUTES: Routes = [
@@ -42,6 +43,7 @@ export const E2E_APP_ROUTES: Routes = [
{path: 'radio', component: SimpleRadioButtons},
{path: 'sidenav', component: SidenavE2E},
{path: 'slide-toggle', component: SlideToggleE2E},
+ {path: 'stepper', component: StepperOverviewExample},
{path: 'tabs', component: BasicTabs},
{path: 'cards', component: CardFancyExample},
{path: 'toolbar', component: ToolbarMultirowExample},
diff --git a/src/lib/stepper/stepper.md b/src/lib/stepper/stepper.md
index 54e273068cf..cf338133047 100644
--- a/src/lib/stepper/stepper.md
+++ b/src/lib/stepper/stepper.md
@@ -1,5 +1,7 @@
Angular Material's stepper provides a wizard-like workflow by dividing content into logical steps.
+
+
Material stepper builds on the foundation of the CDK stepper that is responsible for the logic
that drives a stepped workflow. Material stepper extends the CDK stepper and has Material Design
styling.
diff --git a/src/material-examples/example-module.ts b/src/material-examples/example-module.ts
index 8d417f5a9ca..0c6bdad9b54 100644
--- a/src/material-examples/example-module.ts
+++ b/src/material-examples/example-module.ts
@@ -74,6 +74,7 @@ import {SliderOverviewExample} from './slider-overview/slider-overview-example';
import {PizzaPartyComponent,SnackBarComponentExample} from './snack-bar-component/snack-bar-component-example';
import {SnackBarOverviewExample} from './snack-bar-overview/snack-bar-overview-example';
import {SortOverviewExample} from './sort-overview/sort-overview-example';
+import {StepperOverviewExample} from './stepper-overview/stepper-overview-example';
import {TableBasicExample} from './table-basic/table-basic-example';
import {TableFilteringExample} from './table-filtering/table-filtering-example';
import {TableHttpExample} from './table-http/table-http-example';
@@ -454,6 +455,12 @@ export const EXAMPLE_COMPONENTS = {
additionalFiles: null,
selectorName: null
},
+ 'stepper-overview': {
+ title: 'Stepper overview',
+ component: StepperOverviewExample,
+ additionalFiles: null,
+ selectorName: null
+ },
'table-basic': {
title: 'Basic table',
component: TableBasicExample,
@@ -590,6 +597,7 @@ export const EXAMPLE_LIST = [
PizzaPartyComponent,SnackBarComponentExample,
SnackBarOverviewExample,
SortOverviewExample,
+ StepperOverviewExample,
TableBasicExample,
TableFilteringExample,
TableHttpExample,
diff --git a/src/material-examples/material-module.ts b/src/material-examples/material-module.ts
index 1b7bca44a48..34309d98dbb 100644
--- a/src/material-examples/material-module.ts
+++ b/src/material-examples/material-module.ts
@@ -8,7 +8,7 @@ import {
MdListModule, MdMenuModule, MdProgressBarModule, MdProgressSpinnerModule,
MdRadioModule, MdSelectModule, MdSidenavModule, MdSliderModule, MdSortModule,
MdSlideToggleModule, MdSnackBarModule, MdTableModule, MdTabsModule, MdToolbarModule,
- MdTooltipModule, MdFormFieldModule, MdExpansionModule
+ MdTooltipModule, MdFormFieldModule, MdExpansionModule, MdStepperModule
} from '@angular/material';
@NgModule({
@@ -37,6 +37,7 @@ import {
MdSliderModule,
MdSidenavModule,
MdSnackBarModule,
+ MdStepperModule,
MdTabsModule,
MdToolbarModule,
MdTooltipModule,
diff --git a/src/material-examples/public_api.ts b/src/material-examples/public_api.ts
index 44e209b7b5a..570355e84a8 100644
--- a/src/material-examples/public_api.ts
+++ b/src/material-examples/public_api.ts
@@ -7,3 +7,4 @@ export * from './card-fancy/card-fancy-example';
export * from './toolbar-multirow/toolbar-multirow-example';
export * from './button-toggle-overview/button-toggle-overview-example';
export * from './expansion-overview/expansion-overview-example';
+export * from './stepper-overview/stepper-overview-example';
diff --git a/src/material-examples/stepper-overview/stepper-overview-example.css b/src/material-examples/stepper-overview/stepper-overview-example.css
new file mode 100644
index 00000000000..7432308753e
--- /dev/null
+++ b/src/material-examples/stepper-overview/stepper-overview-example.css
@@ -0,0 +1 @@
+/** No CSS for this example */
diff --git a/src/material-examples/stepper-overview/stepper-overview-example.html b/src/material-examples/stepper-overview/stepper-overview-example.html
new file mode 100644
index 00000000000..4e4408a1bec
--- /dev/null
+++ b/src/material-examples/stepper-overview/stepper-overview-example.html
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+ Done
+ You are now done.
+
+
+
+
+
diff --git a/src/material-examples/stepper-overview/stepper-overview-example.ts b/src/material-examples/stepper-overview/stepper-overview-example.ts
new file mode 100644
index 00000000000..717dcb5d0a9
--- /dev/null
+++ b/src/material-examples/stepper-overview/stepper-overview-example.ts
@@ -0,0 +1,27 @@
+import {Component} from '@angular/core';
+import {FormBuilder, FormGroup, Validators} from '@angular/forms';
+
+/**
+ * @title Stepper overview
+ */
+@Component({
+ selector: 'stepper-overview-example',
+ templateUrl: 'stepper-overview-example.html',
+ styleUrls: ['stepper-overview-example.css']
+})
+export class StepperOverviewExample {
+ isLinear = false;
+ firstFormGroup: FormGroup;
+ secondFormGroup: FormGroup;
+
+ constructor(private _formBuilder: FormBuilder) { }
+
+ ngOnInit() {
+ this.firstFormGroup = this._formBuilder.group({
+ firstCtrl: ['', Validators.required]
+ });
+ this.secondFormGroup = this._formBuilder.group({
+ secondCtrl: ['', Validators.required]
+ });
+ }
+}