diff --git a/CHANGELOG.md b/CHANGELOG.md
index f47bf8b1bfe..1e903271216 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,6 @@
# [`master`](https://github.com/elastic/eui/tree/master)
+- Added `EuiSteps` component
- Added `EuiHealth` components for status checks [(#158)](https://github.com/elastic/eui/pull/158)
- Cleaned up styling for checkboxes, switches, and radios [(#158)](https://github.com/elastic/eui/pull/158)
- Form `disabled` states are now more consistant [(#158)](https://github.com/elastic/eui/pull/158)
@@ -51,3 +52,5 @@
# [`0.0.1`](https://github.com/elastic/eui/tree/v0.0.1) Initial Release
- Initial public release
+
+
diff --git a/src-docs/src/services/routes/routes.js b/src-docs/src/services/routes/routes.js
index 4970ea61e65..7aa6bfc6069 100644
--- a/src-docs/src/services/routes/routes.js
+++ b/src-docs/src/services/routes/routes.js
@@ -109,6 +109,9 @@ import { SideNavExample }
import { SpacerExample }
from '../../views/spacer/spacer_example';
+import { StepsExample }
+ from '../../views/steps/steps_example';
+
import { TableExample }
from '../../views/table/table_example';
@@ -200,6 +203,7 @@ const components = [
ProgressExample,
SideNavExample,
SpacerExample,
+ StepsExample,
TableExample,
TabsExample,
TextExample,
diff --git a/src-docs/src/views/steps/heading_element_steps.js b/src-docs/src/views/steps/heading_element_steps.js
new file mode 100644
index 00000000000..062678814ed
--- /dev/null
+++ b/src-docs/src/views/steps/heading_element_steps.js
@@ -0,0 +1,22 @@
+import React from 'react';
+
+import {
+ EuiSteps,
+} from '../../../../src/components';
+
+const steps = [
+ {
+ title: 'inspect me',
+ children:
Did you notice the step title is inside a Heading 2 element?
+ }
+];
+
+export default () => (
+
+
Heading 1
+
+
+);
diff --git a/src-docs/src/views/steps/steps.js b/src-docs/src/views/steps/steps.js
new file mode 100644
index 00000000000..167d7cefb66
--- /dev/null
+++ b/src-docs/src/views/steps/steps.js
@@ -0,0 +1,59 @@
+import React from 'react';
+
+import {
+ EuiCode,
+ EuiSpacer,
+ EuiSteps,
+ EuiText,
+} from '../../../../src/components';
+
+const firstSetOfSteps = [
+ {
+ title: 'step 1',
+ children: Do this first
+ },
+ {
+ title: 'step 2',
+ children: Then this
+ },
+ {
+ title: 'step 3',
+ children: And finally, do this
+ },
+];
+
+const nextSetOfSteps = [
+ {
+ title: 'good step',
+ children: Do this first
+ },
+ {
+ title: 'better step',
+ children: Then this
+ },
+ {
+ title: 'best step',
+ children: And finally, do this
+ },
+];
+
+export default () => (
+
+
+
+
+
+
+ Set firstStepNumber to continue step numbering after any type of break in the content
+
+
+
+
+
+
+);
diff --git a/src-docs/src/views/steps/steps_example.js b/src-docs/src/views/steps/steps_example.js
new file mode 100644
index 00000000000..9a89578965b
--- /dev/null
+++ b/src-docs/src/views/steps/steps_example.js
@@ -0,0 +1,51 @@
+import React from 'react';
+
+import { renderToHtml } from '../../services';
+
+import {
+ GuideSectionTypes,
+} from '../../components';
+
+import Steps from './steps';
+const stepsSource = require('!!raw-loader!./steps');
+const stepsHtml = renderToHtml(Steps);
+
+import HeadingElementSteps from './heading_element_steps';
+const headingElementStepsSource = require('!!raw-loader!./heading_element_steps');
+const headingElementStepsHtml = renderToHtml(HeadingElementSteps);
+
+export const StepsExample = {
+ title: 'Steps',
+ sections: [{
+ title: 'Steps',
+ source: [{
+ type: GuideSectionTypes.JS,
+ code: stepsSource,
+ }, {
+ type: GuideSectionTypes.HTML,
+ code: stepsHtml,
+ }],
+ text: (
+
+ Numbered steps
+
+ ),
+ demo: ,
+ },
+ {
+ title: 'Heading Element Steps',
+ source: [{
+ type: GuideSectionTypes.JS,
+ code: headingElementStepsSource,
+ }, {
+ type: GuideSectionTypes.HTML,
+ code: headingElementStepsHtml,
+ }],
+ text: (
+
+ something something better accessibility
+
+ ),
+ demo: ,
+ }],
+};
diff --git a/src/components/index.js b/src/components/index.js
index cc0db64f9f1..3f512fe7c6c 100644
--- a/src/components/index.js
+++ b/src/components/index.js
@@ -174,6 +174,10 @@ export {
EuiSpacer,
} from './spacer';
+export {
+ EuiSteps,
+} from './steps';
+
export {
EuiTable,
EuiTableBody,
diff --git a/src/components/index.scss b/src/components/index.scss
index d794e289452..b538506c0ad 100644
--- a/src/components/index.scss
+++ b/src/components/index.scss
@@ -30,6 +30,7 @@
@import 'progress/index';
@import 'side_nav/index';
@import 'spacer/index';
+@import 'steps/index';
@import 'table/index';
@import 'tabs/index';
@import 'title/index';
diff --git a/src/components/steps/__snapshots__/step.test.js.snap b/src/components/steps/__snapshots__/step.test.js.snap
new file mode 100644
index 00000000000..71be26248e2
--- /dev/null
+++ b/src/components/steps/__snapshots__/step.test.js.snap
@@ -0,0 +1,29 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`EuiStep is rendered 1`] = `
+
+
+
+ 1
+
+
+ First step
+
+
+
+
+`;
diff --git a/src/components/steps/__snapshots__/steps.test.js.snap b/src/components/steps/__snapshots__/steps.test.js.snap
new file mode 100644
index 00000000000..326cd6ed371
--- /dev/null
+++ b/src/components/steps/__snapshots__/steps.test.js.snap
@@ -0,0 +1,235 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`EuiSteps renders step title inside "headingElement" element 1`] = `
+
+
+
+
+ 1
+
+
+ first title
+
+
+
+
+
+
+
+ 2
+
+
+ second title
+
+
+
+
+
+
+
+ 3
+
+
+ third title
+
+
+
+
+ And finally, do this
+
+
+
+
+`;
+
+exports[`EuiSteps renders steps 1`] = `
+
+
+
+
+ 1
+
+
+ first title
+
+
+
+
+
+
+
+ 2
+
+
+ second title
+
+
+
+
+
+
+
+ 3
+
+
+ third title
+
+
+
+
+ And finally, do this
+
+
+
+
+`;
+
+exports[`EuiSteps renders steps with firstStepNumber 1`] = `
+
+
+
+
+ 10
+
+
+ first title
+
+
+
+
+
+
+
+ 11
+
+
+ second title
+
+
+
+
+
+
+
+ 12
+
+
+ third title
+
+
+
+
+ And finally, do this
+
+
+
+
+`;
diff --git a/src/components/steps/_index.scss b/src/components/steps/_index.scss
new file mode 100644
index 00000000000..c64a8f5a532
--- /dev/null
+++ b/src/components/steps/_index.scss
@@ -0,0 +1 @@
+@import 'steps';
diff --git a/src/components/steps/_steps.scss b/src/components/steps/_steps.scss
new file mode 100644
index 00000000000..51c571ab08a
--- /dev/null
+++ b/src/components/steps/_steps.scss
@@ -0,0 +1,27 @@
+.euiSteps {
+
+}
+
+.euiStepNumber {
+ width: 32px;
+ height: 32px;
+ display: inline-block;
+ line-height: 32px;
+ text-align: center;
+ color: #FFF;
+ border-radius: 100%;
+ background-color: #0079a5;
+}
+
+.euiStepTitle {
+ display: inline-block;
+ margin-left: 16px;
+}
+
+.euiStepContent {
+ border-left: medium solid #D9D9D9;
+ margin-top: 8px;
+ margin-bottom: 8px;
+ margin-left: 16px;
+ padding-left: 24px;
+}
diff --git a/src/components/steps/index.js b/src/components/steps/index.js
new file mode 100644
index 00000000000..c197c4f0b27
--- /dev/null
+++ b/src/components/steps/index.js
@@ -0,0 +1,3 @@
+export {
+ EuiSteps,
+} from './steps';
diff --git a/src/components/steps/step.js b/src/components/steps/step.js
new file mode 100644
index 00000000000..b59d78e526f
--- /dev/null
+++ b/src/components/steps/step.js
@@ -0,0 +1,46 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import classNames from 'classnames';
+
+import {
+ EuiTitle
+} from '../title';
+
+export const EuiStep = ({
+ className,
+ children,
+ headingElement,
+ step,
+ title,
+ ...rest
+}) => {
+ const classes = classNames('euiStep', className);
+ return (
+
+
+
+
+ {step}
+
+
+ {React.createElement(headingElement, null, title)}
+
+
+
+
+ {children}
+
+
+
+ );
+};
+
+EuiStep.propTypes = {
+ children: PropTypes.node.isRequired,
+ step: PropTypes.number.isRequired,
+ title: PropTypes.string.isRequired,
+ headingElement: PropTypes.string.isRequired,
+};
diff --git a/src/components/steps/step.test.js b/src/components/steps/step.test.js
new file mode 100644
index 00000000000..3393d03e6eb
--- /dev/null
+++ b/src/components/steps/step.test.js
@@ -0,0 +1,23 @@
+import React from 'react';
+import { render } from 'enzyme';
+import { requiredProps } from '../../test/required_props';
+
+import { EuiStep } from './step';
+
+describe('EuiStep', () => {
+ test('is rendered', () => {
+ const stepContent = (Do this
);
+ const component = render(
+
+ );
+
+ expect(component)
+ .toMatchSnapshot();
+ });
+});
diff --git a/src/components/steps/steps.js b/src/components/steps/steps.js
new file mode 100644
index 00000000000..e888f90c202
--- /dev/null
+++ b/src/components/steps/steps.js
@@ -0,0 +1,64 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import classNames from 'classnames';
+import { EuiStep } from './step';
+
+function renderSteps(steps, firstStepNumber, headingElement) {
+ return steps.map((step, index) => {
+ const {
+ className,
+ children,
+ title,
+ ...rest
+ } = step;
+
+ return (
+
+ {children}
+
+ );
+ });
+}
+
+export const EuiSteps = ({
+ className,
+ firstStepNumber,
+ headingElement,
+ steps,
+ ...rest,
+}) => {
+ const classes = classNames('euiSteps', className);
+
+ return (
+
+ {renderSteps(steps, firstStepNumber, headingElement)}
+
+ );
+};
+
+const stepPropType = PropTypes.shape({
+ title: PropTypes.string.isRequired,
+ children: PropTypes.node
+});
+
+EuiSteps.propTypes = {
+ className: PropTypes.string,
+ firstStepNumber: PropTypes.number,
+ headingElement: PropTypes.string,
+ steps: PropTypes.arrayOf(stepPropType).isRequired,
+};
+
+EuiSteps.defaultProps = {
+ firstStepNumber: 1,
+ headingElement: 'p'
+};
diff --git a/src/components/steps/steps.test.js b/src/components/steps/steps.test.js
new file mode 100644
index 00000000000..4afb3ee40f4
--- /dev/null
+++ b/src/components/steps/steps.test.js
@@ -0,0 +1,49 @@
+import React from 'react';
+import { render } from 'enzyme';
+import { requiredProps } from '../../test/required_props';
+
+import { EuiSteps } from './steps';
+
+const steps = [
+ {
+ title: 'first title',
+ children: Do this first
+ },
+ {
+ title: 'second title',
+ children: Then this
+ },
+ {
+ title: 'third title',
+ children: And finally, do this
+ },
+];
+
+describe('EuiSteps', () => {
+ test('renders steps', () => {
+ const component = render(
+
+ );
+
+ expect(component)
+ .toMatchSnapshot();
+ });
+
+ test('renders steps with firstStepNumber', () => {
+ const component = render(
+
+ );
+
+ expect(component)
+ .toMatchSnapshot();
+ });
+
+ test('renders step title inside "headingElement" element', () => {
+ const component = render(
+
+ );
+
+ expect(component)
+ .toMatchSnapshot();
+ });
+});