Repository: uber-web/baseui
Pull request #269 (2018-09-18 01:16:20)

feat(icon): implement icon component
Initial implementation for the Icon component.

### [Live Preview](https://deploy-preview-269--baseui.netlify.com/?knob-Size=48px&knob-Color=0&knob-Button%20Kind=primary&selectedKind=Icon&selectedStory=Icon&full=0&addons=1&stories=1&panelRight=0&addonPanel=REACT_STORYBOOK%2Freadme%2Fpanel)

**Progress**
- [x] Basic implementation
- [x] Stories
- [x] Implement all icons (23 / 23)
- [x] Unit Tests

**Questions**

- Should we use names that describe the iconography itself or its semantic meaning? For example, the X icon can be used for both `Delete` and `Close` use cases, so maybe `X` is more appropriate? In theory we could have aliases too.



Patch:
diff --git a/rfcs/icon-component.md b/rfcs/icon-component.md
index 058b3540d..011c062f2 100644
--- a/rfcs/icon-component.md
+++ b/rfcs/icon-component.md
@@ -1,54 +1,79 @@
 # Icon Component
 
-This is the set of ~16 icons used internally within baseui that are safe to open source. This is not the set of uber-specific icons published internally as @uber/icons (though the API is intended to align with that to reduce confusion).
+## Basic Usage
 
-![image](https://user-images.githubusercontent.com/875591/45131331-51e8c500-b141-11e8-898d-ead83d44b345.png)
+```javascript
+import * as React from 'react';
+import ArrowLeft from 'baseui/icon/arrow-left';
+
+export default () => (
+  <ArrowLeft size="10px" color="#ccc" />
+);
+```
 
-## Usage
+## Advanced Usage
 
 ```javascript
 import * as React from 'react';
-import {LeftArrow} from 'baseui/icon/left-arrow';
+import Delete from 'baseui/icon/delete';
 
 export default () => (
-  <LeftArrow size="10px" color="#ccc" />
+  <Delete
+    overrides={{
+      Svg: {
+        style: {margin: '5px'}
+      }
+    }}
+    size="10px"
+    color="scale300"
+    title="custom a11y title tag"
+  />
 );
 ```
 
-## Exports
+## Usage with Button
 
-* `Icon` (Base Icon component used by other exports below)
+```javascript
+import * as React from 'react';
+import {Button} from 'baseui/button';
+import Upload from 'baseui/icon/upload';
 
-From left-to-right based on the image above:
+export default () => (
+  <Button endEnhancer={() => <Upload />}>Upload</Button>
+);
+```
 
-* `DeleteAlt`
-* `Search`
-* `Delete`
-* `Check`
-* `ArrowUp`
+## Exports
+
+* `Icon` (Base Icon component used by other exports below)
+* `Alert`
 * `ArrowDown`
 * `ArrowLeft`
 * `ArrowRight`
-* `TriangleRight`
-* `TriangleDown`
-* `Upload`
-* `Plus`
+* `ArrowUp`
+* `Check`
+* `CheckIndeterminate`
+* `ChevronLeft`
+* `ChevronRight`
+* `Delete`
+* `DeleteAlt`
+* `Filter`
 * `Grab`
-* `Alert`
 * `Menu`
-* `ChevronRight`
-* `ChevronLeft`
-* `Spinner`
 * `Overflow`
+* `Plus`
+* `Search`
+* `Spinner`
+* `TriangleDown`
 * `TriangleLeft`
+* `TriangleRight`
 * `TriangleUp`
-* `Filter`
-* `CheckIndeterminate`
+* `Upload`
 
 ## `Icon` API
 
 * `size: number|string` - Optional, Defaults to `scale500` (12px)
-  Size of element, will be passed to the svg width/height style. Can also be a baseui `theme.sizing` constant like `sizing500`.
+  Size of element, will be passed to the svg width/height style. Can also be a baseui `theme.sizing` constant like `scale500`.
 * `color: string` - Optional, Defaults to `currentColor`
   Color of icon, will be used as svg fill
 * `title: string` - Optional
diff --git a/src/icon/README.md b/src/icon/README.md
new file mode 100644
index 000000000..4252283eb
--- /dev/null
+++ b/src/icon/README.md
@@ -0,0 +1,11 @@
+# Icon
+
+See rfcs/icon-component.md for documentation on how to use icons
+
+### Development
+
+The source data for icons should be placed in the svg/ folder.
+
+`icon-template.txt` can be used to change what the React component for icons look like
+
+Run `yarn babel-node ./src/icon/build-icons.js` to build all icons.
diff --git a/src/icon/alert.js b/src/icon/alert.js
new file mode 100644
index 000000000..0657c1f3e
--- /dev/null
+++ b/src/icon/alert.js
@@ -0,0 +1,24 @@
+/*
+Copyright (c) 2018 Uber Technologies, Inc.
+
+This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*/
+// @flow
+// BASEUI-GENERATED-REACT-ICON
+// DO NOT EDIT THIS FILE DIRECTLY, SEE README.md
+import * as React from 'react';
+import Icon from './icon';
+import type {IconPropsT} from './types';
+
+export default function Alert(props: IconPropsT) {
+  return (
+    <Icon title="Alert" viewBox="0 0 24 24" {...props}>
+      <path
+        fillRule="evenodd"
+        clipRule="evenodd"
+        d="M12 21C16.9706 21 21 16.9706 21 12C21 7.02945 16.9706 3 12 3C7.02942 3 3 7.02945 3 12C3 16.9706 7.02942 21 12 21ZM12 6C12.5523 6 13 6.44772 13 7V13C13 13.5523 12.5523 14 12 14C11.4477 14 11 13.5523 11 13V7C11 6.44772 11.4477 6 12 6ZM13 17C13 17.5523 12.5523 18 12 18C11.4477 18 11 17.5523 11 17C11 16.4477 11.4477 16 12 16C12.5523 16 13 16.4477 13 17Z"
+      />
+    </Icon>
+  );
+}
diff --git a/src/icon/arrow-down.js b/src/icon/arrow-down.js
new file mode 100644
index 000000000..b5f6b9fb5
--- /dev/null
+++ b/src/icon/arrow-down.js
@@ -0,0 +1,24 @@
+/*
+Copyright (c) 2018 Uber Technologies, Inc.
+
+This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*/
+// @flow
+// BASEUI-GENERATED-REACT-ICON
+// DO NOT EDIT THIS FILE DIRECTLY, SEE README.md
+import * as React from 'react';
+import Icon from './icon';
+import type {IconPropsT} from './types';
+
+export default function ArrowDown(props: IconPropsT) {
+  return (
+    <Icon title="Arrow Down" viewBox="0 0 24 24" {...props}>
+      <path
+        fillRule="evenodd"
+        clipRule="evenodd"
+        d="M12 6C12.5523 6 13 6.44772 13 7V14.5858L15.2929 12.2929C15.6834 11.9024 16.3166 11.9024 16.7071 12.2929C17.0976 12.6834 17.0976 13.3166 16.7071 13.7071L12.7071 17.7071C12.3166 18.0976 11.6834 18.0976 11.2929 17.7071L7.29289 13.7071C6.90237 13.3166 6.90237 12.6834 7.29289 12.2929C7.68342 11.9024 8.31658 11.9024 8.70711 12.2929L11 14.5858V7C11 6.44772 11.4477 6 12 6Z"
+      />
+    </Icon>
+  );
+}
diff --git a/src/icon/arrow-left.js b/src/icon/arrow-left.js
new file mode 100644
index 000000000..2b2321d04
--- /dev/null
+++ b/src/icon/arrow-left.js
@@ -0,0 +1,24 @@
+/*
+Copyright (c) 2018 Uber Technologies, Inc.
+
+This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*/
+// @flow
+// BASEUI-GENERATED-REACT-ICON
+// DO NOT EDIT THIS FILE DIRECTLY, SEE README.md
+import * as React from 'react';
+import Icon from './icon';
+import type {IconPropsT} from './types';
+
+export default function ArrowLeft(props: IconPropsT) {
+  return (
+    <Icon title="Arrow Left" viewBox="0 0 24 24" {...props}>
+      <path
+        fillRule="evenodd"
+        clipRule="evenodd"
+        d="M6.29289 11.2929C5.90237 11.6834 5.90237 12.3166 6.29289 12.7071L10.2929 16.7071C10.6834 17.0976 11.3166 17.0976 11.7071 16.7071C12.0976 16.3166 12.0976 15.6834 11.7071 15.2929L9.41421 13H17C17.5523 13 18 12.5523 18 12C18 11.4477 17.5523 11 17 11H9.41421L11.7071 8.70711C12.0976 8.31658 12.0976 7.68342 11.7071 7.29289C11.3166 6.90237 10.6834 6.90237 10.2929 7.29289L6.29289 11.2929Z"
+      />
+    </Icon>
+  );
+}
diff --git a/src/icon/arrow-right.js b/src/icon/arrow-right.js
new file mode 100644
index 000000000..a5fce6d6c
--- /dev/null
+++ b/src/icon/arrow-right.js
@@ -0,0 +1,24 @@
+/*
+Copyright (c) 2018 Uber Technologies, Inc.
+
+This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*/
+// @flow
+// BASEUI-GENERATED-REACT-ICON
+// DO NOT EDIT THIS FILE DIRECTLY, SEE README.md
+import * as React from 'react';
+import Icon from './icon';
+import type {IconPropsT} from './types';
+
+export default function ArrowRight(props: IconPropsT) {
+  return (
+    <Icon title="Arrow Right" viewBox="0 0 24 24" {...props}>
+      <path
+        fillRule="evenodd"
+        clipRule="evenodd"
+        d="M6 12C6 12.5523 6.44772 13 7 13H14.5858L12.2929 15.2929C11.9024 15.6834 11.9024 16.3166 12.2929 16.7071C12.6834 17.0976 13.3166 17.0976 13.7071 16.7071L17.7071 12.7071C17.8946 12.5196 18 12.2652 18 12C18 11.7348 17.8946 11.4804 17.7071 11.2929L13.7071 7.29289C13.3166 6.90237 12.6834 6.90237 12.2929 7.29289C11.9024 7.68342 11.9024 8.31658 12.2929 8.70711L14.5858 11H7C6.44772 11 6 11.4477 6 12Z"
+      />
+    </Icon>
+  );
+}
diff --git a/src/icon/arrow-up.js b/src/icon/arrow-up.js
new file mode 100644
index 000000000..992104e26
--- /dev/null
+++ b/src/icon/arrow-up.js
@@ -0,0 +1,24 @@
+/*
+Copyright (c) 2018 Uber Technologies, Inc.
+
+This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*/
+// @flow
+// BASEUI-GENERATED-REACT-ICON
+// DO NOT EDIT THIS FILE DIRECTLY, SEE README.md
+import * as React from 'react';
+import Icon from './icon';
+import type {IconPropsT} from './types';
+
+export default function ArrowUp(props: IconPropsT) {
+  return (
+    <Icon title="Arrow Up" viewBox="0 0 24 24" {...props}>
+      <path
+        fillRule="evenodd"
+        clipRule="evenodd"
+        d="M11.2929 6.29289C11.6834 5.90237 12.3166 5.90237 12.7071 6.29289L16.7071 10.2929C17.0976 10.6834 17.0976 11.3166 16.7071 11.7071C16.3166 12.0976 15.6834 12.0976 15.2929 11.7071L13 9.41421V17C13 17.5523 12.5523 18 12 18C11.4477 18 11 17.5523 11 17V9.41421L8.70711 11.7071C8.31658 12.0976 7.68342 12.0976 7.29289 11.7071C6.90237 11.3166 6.90237 10.6834 7.29289 10.2929L11.2929 6.29289Z"
+      />
+    </Icon>
+  );
+}
diff --git a/src/icon/build-icons.js b/src/icon/build-icons.js
new file mode 100755
index 000000000..1f2db5e3c
--- /dev/null
+++ b/src/icon/build-icons.js
@@ -0,0 +1,111 @@
+#!/usr/bin/env node
+/*
+Copyright (c) 2018 Uber Technologies, Inc.
+ This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*/
+// @flow
+/* eslint-env node*/
+import fs from 'fs';
+import path from 'path';
+import prettier from 'prettier';
+
+function capitalize(str: string): string {
+  return str.charAt(0).toUpperCase() + str.slice(1);
+}
+
+function pascalCase(str: string): string {
+  return str
+    .split('-')
+    .map(capitalize)
+    .join('');
+}
+
+function titleCase(str: string): string {
+  return str
+    .split('-')
+    .map(capitalize)
+    .join(' ');
+}
+
+// transform svg string to properly styled jsx
+function reactify(svgString: string): string {
+  return svgString
+    .replace(/<\/?svg[^>]*>/gm, '')
+    .replace(/^\s*\n/gm, '')
+    .replace(/\n$/, '')
+    .replace(/\t/g, '  ')
+    .replace(/fill-rule/g, 'fillRule')
+    .replace(/clip-rule/g, 'clipRule')
+    .replace(/fill-opacity/g, 'fillOpacity')
+    .trim();
+}
+
+function cleanOldIcons() {
+  const allJsFiles = fs
+    .readdirSync(path.resolve(__dirname))
+    .filter(f => f.endsWith('.js'));
+  allJsFiles.forEach(f => {
+    if (
+      fs
+        .readFileSync(path.resolve(__dirname, f), 'utf8')
+        .match(/^\/\/ BASEUI-GENERATED-REACT-ICON/m)
+    ) {
+      fs.unlinkSync(path.resolve(__dirname, f));
+    }
+  });
+}
+
+async function generateNewIcons() {
+  const iconTemplate = fs.readFileSync(
+    path.resolve(__dirname, './icon-template.txt'),
+    'utf8',
+  );
+  const svgs = fs
+    .readdirSync(path.resolve(__dirname, './svg'))
+    .filter(f => f.endsWith('.svg'));
+
+  const prettierOptions = (await prettier.resolveConfig(__dirname)) || {};
+  const iconExports = [];
+
+  svgs.forEach(async svgFilename => {
+    const svgFile = svgFilename.split('.')[0];
+    const componentName = pascalCase(svgFile);
+    iconExports.push(
+      `export {default as ${componentName}} from './${svgFile}';`,
+    );
+
+    const svgFileContents = fs.readFileSync(
+      path.resolve(__dirname, `./svg/${svgFilename}`),
+      'utf8',
+    );
+
+    const iconProps = [`title="${titleCase(svgFile)}"`];
+
+    const viewBox = svgFileContents.match(/viewBox="[^"]+"/);
+    if (viewBox) {
+      iconProps.push(viewBox[0]);
+    }
+
+    let result = iconTemplate
+      .replace('%%ICON_NAME%%', componentName)
+      .replace('%%ICON_PROPS%%', iconProps.join(' '))
+      .replace('%%ICON_PATH%%', reactify(svgFileContents));
+
+    fs.writeFileSync(
+      path.resolve(__dirname, `./${svgFile}.js`),
+      prettier.format(result, {parser: 'babylon', ...prettierOptions}),
+    );
+  });
+
+  fs.writeFileSync(
+    path.resolve(__dirname, `./icon-exports.js`),
+    `// @flow\n${iconExports.join('\n')}\n`,
+  );
+
+  // eslint-disable-next-line no-console
+  console.log(`Wrote ${svgs.length} icon(s)`);
+}
+
+cleanOldIcons();
+generateNewIcons();
diff --git a/src/icon/check-indeterminate.js b/src/icon/check-indeterminate.js
new file mode 100644
index 000000000..401c78e36
--- /dev/null
+++ b/src/icon/check-indeterminate.js
@@ -0,0 +1,24 @@
+/*
+Copyright (c) 2018 Uber Technologies, Inc.
+
+This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*/
+// @flow
+// BASEUI-GENERATED-REACT-ICON
+// DO NOT EDIT THIS FILE DIRECTLY, SEE README.md
+import * as React from 'react';
+import Icon from './icon';
+import type {IconPropsT} from './types';
+
+export default function CheckIndeterminate(props: IconPropsT) {
+  return (
+    <Icon title="Check Indeterminate" viewBox="0 0 24 24" {...props}>
+      <path
+        fillRule="evenodd"
+        clipRule="evenodd"
+        d="M6 12C6 11.4477 6.44772 11 7 11H17C17.5523 11 18 11.4477 18 12C18 12.5523 17.5523 13 17 13H7C6.44772 13 6 12.5523 6 12Z"
+      />
+    </Icon>
+  );
+}
diff --git a/src/icon/check.js b/src/icon/check.js
new file mode 100644
index 000000000..9acfa0895
--- /dev/null
+++ b/src/icon/check.js
@@ -0,0 +1,24 @@
+/*
+Copyright (c) 2018 Uber Technologies, Inc.
+
+This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*/
+// @flow
+// BASEUI-GENERATED-REACT-ICON
+// DO NOT EDIT THIS FILE DIRECTLY, SEE README.md
+import * as React from 'react';
+import Icon from './icon';
+import type {IconPropsT} from './types';
+
+export default function Check(props: IconPropsT) {
+  return (
+    <Icon title="Check" viewBox="0 0 24 24" {...props}>
+      <path
+        fillRule="evenodd"
+        clipRule="evenodd"
+        d="M17.6 7.20006C18.0418 7.53143 18.1314 8.15823 17.8 8.60006L11.8 16.6001C11.6261 16.832 11.3601 16.977 11.0709 16.9975C10.7817 17.0181 10.4979 16.9122 10.2929 16.7072L7.29289 13.7072C6.90237 13.3166 6.90237 12.6835 7.29289 12.293C7.68342 11.9024 8.31658 11.9024 8.70711 12.293L10.8918 14.4777L16.2 7.40006C16.5314 6.95823 17.1582 6.86869 17.6 7.20006Z"
+      />
+    </Icon>
+  );
+}
diff --git a/src/icon/chevron-left.js b/src/icon/chevron-left.js
new file mode 100644
index 000000000..d11552452
--- /dev/null
+++ b/src/icon/chevron-left.js
@@ -0,0 +1,24 @@
+/*
+Copyright (c) 2018 Uber Technologies, Inc.
+
+This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*/
+// @flow
+// BASEUI-GENERATED-REACT-ICON
+// DO NOT EDIT THIS FILE DIRECTLY, SEE README.md
+import * as React from 'react';
+import Icon from './icon';
+import type {IconPropsT} from './types';
+
+export default function ChevronLeft(props: IconPropsT) {
+  return (
+    <Icon title="Chevron Left" viewBox="0 0 24 24" {...props}>
+      <path
+        fillRule="evenodd"
+        clipRule="evenodd"
+        d="M9 12C9 12.2652 9.10536 12.5196 9.29289 12.7071L13.2929 16.7071C13.6834 17.0976 14.3166 17.0976 14.7071 16.7071C15.0976 16.3166 15.0976 15.6834 14.7071 15.2929L11.4142 12L14.7071 8.70711C15.0976 8.31658 15.0976 7.68342 14.7071 7.29289C14.3166 6.90237 13.6834 6.90237 13.2929 7.29289L9.29289 11.2929C9.10536 11.4804 9 11.7348 9 12Z"
+      />
+    </Icon>
+  );
+}
diff --git a/src/icon/chevron-right.js b/src/icon/chevron-right.js
new file mode 100644
index 000000000..15a521f2d
--- /dev/null
+++ b/src/icon/chevron-right.js
@@ -0,0 +1,24 @@
+/*
+Copyright (c) 2018 Uber Technologies, Inc.
+
+This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*/
+// @flow
+// BASEUI-GENERATED-REACT-ICON
+// DO NOT EDIT THIS FILE DIRECTLY, SEE README.md
+import * as React from 'react';
+import Icon from './icon';
+import type {IconPropsT} from './types';
+
+export default function ChevronRight(props: IconPropsT) {
+  return (
+    <Icon title="Chevron Right" viewBox="0 0 24 24" {...props}>
+      <path
+        fillRule="evenodd"
+        clipRule="evenodd"
+        d="M9.29289 7.29289C8.90237 7.68342 8.90237 8.31658 9.29289 8.70711L12.5858 12L9.29289 15.2929C8.90237 15.6834 8.90237 16.3166 9.29289 16.7071C9.68342 17.0976 10.3166 17.0976 10.7071 16.7071L14.7071 12.7071C14.8946 12.5196 15 12.2652 15 12C15 11.7348 14.8946 11.4804 14.7071 11.2929L10.7071 7.29289C10.3166 6.90237 9.68342 6.90237 9.29289 7.29289Z"
+      />
+    </Icon>
+  );
+}
diff --git a/src/icon/delete-alt.js b/src/icon/delete-alt.js
new file mode 100644
index 000000000..7d923a5a7
--- /dev/null
+++ b/src/icon/delete-alt.js
@@ -0,0 +1,24 @@
+/*
+Copyright (c) 2018 Uber Technologies, Inc.
+
+This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*/
+// @flow
+// BASEUI-GENERATED-REACT-ICON
+// DO NOT EDIT THIS FILE DIRECTLY, SEE README.md
+import * as React from 'react';
+import Icon from './icon';
+import type {IconPropsT} from './types';
+
+export default function DeleteAlt(props: IconPropsT) {
+  return (
+    <Icon title="Delete Alt" viewBox="0 0 24 24" {...props}>
+      <path
+        fillRule="evenodd"
+        clipRule="evenodd"
+        d="M12 20C16.4183 20 20 16.4183 20 12C20 7.58173 16.4183 4 12 4C7.58173 4 4 7.58173 4 12C4 16.4183 7.58173 20 12 20ZM10.0303 8.96967C9.73743 8.67679 9.26257 8.67679 8.96967 8.96967C8.67676 9.26257 8.67676 9.73743 8.96967 10.0303L10.9393 12L8.96967 13.9697C8.67676 14.2626 8.67676 14.7374 8.96967 15.0303C9.26257 15.3232 9.73743 15.3232 10.0303 15.0303L12 13.0607L13.9697 15.0303C14.2626 15.3232 14.7374 15.3232 15.0303 15.0303C15.3232 14.7374 15.3232 14.2626 15.0303 13.9697L13.0607 12L15.0303 10.0303C15.3232 9.73743 15.3232 9.26257 15.0303 8.96967C14.7374 8.67679 14.2626 8.67679 13.9697 8.96967L12 10.9393L10.0303 8.96967Z"
+      />
+    </Icon>
+  );
+}
diff --git a/src/icon/delete.js b/src/icon/delete.js
new file mode 100644
index 000000000..9fb744f5f
--- /dev/null
+++ b/src/icon/delete.js
@@ -0,0 +1,24 @@
+/*
+Copyright (c) 2018 Uber Technologies, Inc.
+
+This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*/
+// @flow
+// BASEUI-GENERATED-REACT-ICON
+// DO NOT EDIT THIS FILE DIRECTLY, SEE README.md
+import * as React from 'react';
+import Icon from './icon';
+import type {IconPropsT} from './types';
+
+export default function Delete(props: IconPropsT) {
+  return (
+    <Icon title="Delete" viewBox="0 0 24 24" {...props}>
+      <path
+        fillRule="evenodd"
+        clipRule="evenodd"
+        d="M7.29289 7.29289C7.68342 6.90237 8.31658 6.90237 8.70711 7.29289L12 10.5858L15.2929 7.29289C15.6834 6.90237 16.3166 6.90237 16.7071 7.29289C17.0976 7.68342 17.0976 8.31658 16.7071 8.70711L13.4142 12L16.7071 15.2929C17.0976 15.6834 17.0976 16.3166 16.7071 16.7071C16.3166 17.0976 15.6834 17.0976 15.2929 16.7071L12 13.4142L8.70711 16.7071C8.31658 17.0976 7.68342 17.0976 7.29289 16.7071C6.90237 16.3166 6.90237 15.6834 7.29289 15.2929L10.5858 12L7.29289 8.70711C6.90237 8.31658 6.90237 7.68342 7.29289 7.29289Z"
+      />
+    </Icon>
+  );
+}
diff --git a/src/icon/examples.js b/src/icon/examples.js
new file mode 100644
index 000000000..b33424ed3
--- /dev/null
+++ b/src/icon/examples.js
@@ -0,0 +1,112 @@
+/*
+Copyright (c) 2018 Uber Technologies, Inc.
+
+This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*/
+// @flow
+import * as React from 'react';
+import {
+  number as numberKnob,
+  select as selectKnob,
+} from '@storybook/addon-knobs';
+
+import {styled} from '../styles';
+import {Button, KIND} from '../button';
+import * as Icons from './icon-exports';
+
+const Centered = styled('div', {
+  position: 'relative',
+  display: 'flex',
+  flexDirection: 'column',
+  justifyContent: 'center',
+  alignItems: 'center',
+  height: '90vh',
+});
+
+const Grid = styled('div', ({$size}) => ({
+  display: 'grid',
+  gridTemplateColumns: '20% 20% 20% 20% 20%',
+  gridTemplateRows: '20% 20% 20% 20% 20%',
+  width: `${$size}px`,
+  height: `${$size}px`,
+}));
+
+const Buttons = styled('div', {
+  maxWidth: '600px',
+});
+
+const ButtonContainer = styled('div', {
+  display: 'inline-block',
+  margin: '6px',
+});
+
+const GridItem = styled('div', ({row, col}) => ({
+  alignSelf: 'center',
+  justifySelf: 'center',
+}));
+
+export const suite = 'Icon Suite';
+
+export const examples = {
+  SIMPLE_EXAMPLE: 'Icon',
+  BUTTON_EXAMPLE: 'Icons in Button',
+};
+
+export default {
+  [examples.SIMPLE_EXAMPLE]: function Story1() {
+    const size = selectKnob(
+      'Size',
+      ['12px', '16px', '24px', '36px', '48px', '64px'],
+      '48px',
+    );
+    const sizeNum = parseInt(size);
+
+    const hue = numberKnob('Color', 0, {range: true, min: 0, max: 360});
+    const hsl = hue === 0 ? '#000' : `hsl(${hue}, 40%, 40%)`;
+    const numCols = 5;
+
+    return (
+      <Centered>
+        <Grid
+          $size={
+            // Plus two to add some extra padding between items
+            sizeNum * (numCols + 2)
+          }
+        >
+          {Object.keys(Icons).map(key => {
+            const Icon = Icons[key];
+            return (
+              <GridItem key={key}>
+                <Icon size={size} color={hsl} />
+              </GridItem>
+            );
+          })}
+        </Grid>
+      </Centered>
+    );
+  },
+  [examples.BUTTON_EXAMPLE]: function Story1() {
+    const buttonKind = selectKnob(
+      'Button Kind',
+      [KIND.primary, KIND.secondary, KIND.tertiary, KIND.minimal],
+      KIND.primary,
+    );
+    return (
+      <Centered>
+        <Buttons>
+          {Object.keys(Icons).map(key => {
+            const Icon = Icons[key];
+            return (
+              <ButtonContainer key={key}>
+                <Button kind={buttonKind} endEnhancer={() => <Icon />}>
+                  {Icon.name}
+                </Button>
+              </ButtonContainer>
+            );
+          })}
+        </Buttons>
+      </Centered>
+    );
+  },
+};
diff --git a/src/icon/filter.js b/src/icon/filter.js
new file mode 100644
index 000000000..228b12324
--- /dev/null
+++ b/src/icon/filter.js
@@ -0,0 +1,22 @@
+/*
+Copyright (c) 2018 Uber Technologies, Inc.
+
+This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*/
+// @flow
+// BASEUI-GENERATED-REACT-ICON
+// DO NOT EDIT THIS FILE DIRECTLY, SEE README.md
+import * as React from 'react';
+import Icon from './icon';
+import type {IconPropsT} from './types';
+
+export default function Filter(props: IconPropsT) {
+  return (
+    <Icon title="Filter" viewBox="0 0 24 24" {...props}>
+      <rect x="7" y="11" width="10" height="2" rx="1" />
+      <rect x="4" y="7" width="16" height="2" rx="1" />
+      <rect x="10" y="15" width="4" height="2" rx="1" />
+    </Icon>
+  );
+}
diff --git a/src/icon/grab.js b/src/icon/grab.js
new file mode 100644
index 000000000..b6e1ef418
--- /dev/null
+++ b/src/icon/grab.js
@@ -0,0 +1,24 @@
+/*
+Copyright (c) 2018 Uber Technologies, Inc.
+
+This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*/
+// @flow
+// BASEUI-GENERATED-REACT-ICON
+// DO NOT EDIT THIS FILE DIRECTLY, SEE README.md
+import * as React from 'react';
+import Icon from './icon';
+import type {IconPropsT} from './types';
+
+export default function Grab(props: IconPropsT) {
+  return (
+    <Icon title="Grab" viewBox="0 0 24 24" {...props}>
+      <path
+        fillRule="evenodd"
+        clipRule="evenodd"
+        d="M5 8C4.44775 8 4 8.44775 4 9C4 9.55225 4.44775 10 5 10H19C19.5522 10 20 9.55225 20 9C20 8.44775 19.5522 8 19 8H5ZM5 14C4.44775 14 4 14.4478 4 15C4 15.5522 4.44775 16 5 16H19C19.5522 16 20 15.5522 20 15C20 14.4478 19.5522 14 19 14H5Z"
+      />
+    </Icon>
+  );
+}
diff --git a/src/icon/icon-exports.js b/src/icon/icon-exports.js
new file mode 100644
index 000000000..8caa24cf1
--- /dev/null
+++ b/src/icon/icon-exports.js
@@ -0,0 +1,24 @@
+// @flow
+export {default as Alert} from './alert';
+export {default as ArrowDown} from './arrow-down';
+export {default as ArrowLeft} from './arrow-left';
+export {default as ArrowRight} from './arrow-right';
+export {default as ArrowUp} from './arrow-up';
+export {default as CheckIndeterminate} from './check-indeterminate';
+export {default as Check} from './check';
+export {default as ChevronLeft} from './chevron-left';
+export {default as ChevronRight} from './chevron-right';
+export {default as DeleteAlt} from './delete-alt';
+export {default as Delete} from './delete';
+export {default as Filter} from './filter';
+export {default as Grab} from './grab';
+export {default as Menu} from './menu';
+export {default as Overflow} from './overflow';
+export {default as Plus} from './plus';
+export {default as Search} from './search';
+export {default as Spinner} from './spinner';
+export {default as TriangleDown} from './triangle-down';
+export {default as TriangleLeft} from './triangle-left';
+export {default as TriangleRight} from './triangle-right';
+export {default as TriangleUp} from './triangle-up';
+export {default as Upload} from './upload';
diff --git a/src/icon/icon-template.txt b/src/icon/icon-template.txt
new file mode 100644
index 000000000..e484c73c6
--- /dev/null
+++ b/src/icon/icon-template.txt
@@ -0,0 +1,20 @@
+/*
+Copyright (c) 2018 Uber Technologies, Inc.
+
+This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*/
+// @flow
+// BASEUI-GENERATED-REACT-ICON
+// DO NOT EDIT THIS FILE DIRECTLY, SEE README.md
+import * as React from 'react';
+import Icon from './icon';
+import type {IconPropsT} from './types';
+
+export default function %%ICON_NAME%%(props: IconPropsT) {
+  return (
+    <Icon %%ICON_PROPS%% {...props}>
+      %%ICON_PATH%%
+    </Icon>
+  );
+}
diff --git a/src/icon/icon.js b/src/icon/icon.js
new file mode 100644
index 000000000..bf29d0923
--- /dev/null
+++ b/src/icon/icon.js
@@ -0,0 +1,32 @@
+/*
+Copyright (c) 2018 Uber Technologies, Inc.
+
+This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*/
+// @flow
+import * as React from 'react';
+import {getOverrideObject} from '../helpers/overrides';
+import {Svg as StyledSvg} from './styled-components';
+import type {IconPropsT} from './types';
+
+export default function Icon(props: IconPropsT) {
+  const {children, title, overrides = {}, size, color, ...restProps} = props;
+
+  const sharedProps = {
+    $size: size,
+    $color: color,
+  };
+
+  const {component: Svg, props: overrideProps} = getOverrideObject(
+    overrides.Svg,
+    StyledSvg,
+  );
+
+  return (
+    <Svg {...sharedProps} {...restProps} {...overrideProps}>
+      {title ? <title>{title}</title> : null}
+      {children}
+    </Svg>
+  );
+}
diff --git a/src/icon/index.js b/src/icon/index.js
new file mode 100644
index 000000000..73da93ac4
--- /dev/null
+++ b/src/icon/index.js
@@ -0,0 +1,11 @@
+/*
+Copyright (c) 2018 Uber Technologies, Inc.
+
+This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*/
+// @flow
+export {default as Icon} from './icon';
+export {Svg as StyledSvg} from './styled-components';
+export * from './icon-exports';
+export * from './types';
diff --git a/src/icon/menu.js b/src/icon/menu.js
new file mode 100644
index 000000000..2b63943a6
--- /dev/null
+++ b/src/icon/menu.js
@@ -0,0 +1,22 @@
+/*
+Copyright (c) 2018 Uber Technologies, Inc.
+
+This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*/
+// @flow
+// BASEUI-GENERATED-REACT-ICON
+// DO NOT EDIT THIS FILE DIRECTLY, SEE README.md
+import * as React from 'react';
+import Icon from './icon';
+import type {IconPropsT} from './types';
+
+export default function Menu(props: IconPropsT) {
+  return (
+    <Icon title="Menu" viewBox="0 0 24 24" {...props}>
+      <rect x="4" y="11" width="16" height="2" rx="1" />
+      <rect x="4" y="5" width="16" height="2" rx="1" />
+      <rect x="4" y="17" width="16" height="2" rx="1" />
+    </Icon>
+  );
+}
diff --git a/src/icon/overflow.js b/src/icon/overflow.js
new file mode 100644
index 000000000..afb1d396f
--- /dev/null
+++ b/src/icon/overflow.js
@@ -0,0 +1,22 @@
+/*
+Copyright (c) 2018 Uber Technologies, Inc.
+
+This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*/
+// @flow
+// BASEUI-GENERATED-REACT-ICON
+// DO NOT EDIT THIS FILE DIRECTLY, SEE README.md
+import * as React from 'react';
+import Icon from './icon';
+import type {IconPropsT} from './types';
+
+export default function Overflow(props: IconPropsT) {
+  return (
+    <Icon title="Overflow" viewBox="0 0 24 24" {...props}>
+      <circle cx="6" cy="12" r="2" />
+      <circle cx="12" cy="12" r="2" />
+      <circle cx="18" cy="12" r="2" />
+    </Icon>
+  );
+}
diff --git a/src/icon/plus.js b/src/icon/plus.js
new file mode 100644
index 000000000..248ae65c7
--- /dev/null
+++ b/src/icon/plus.js
@@ -0,0 +1,24 @@
+/*
+Copyright (c) 2018 Uber Technologies, Inc.
+
+This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*/
+// @flow
+// BASEUI-GENERATED-REACT-ICON
+// DO NOT EDIT THIS FILE DIRECTLY, SEE README.md
+import * as React from 'react';
+import Icon from './icon';
+import type {IconPropsT} from './types';
+
+export default function Plus(props: IconPropsT) {
+  return (
+    <Icon title="Plus" viewBox="0 0 24 24" {...props}>
+      <path
+        fillRule="evenodd"
+        clipRule="evenodd"
+        d="M12 5C12.5523 5 13 5.44772 13 6V11L18 11C18.5523 11 19 11.4477 19 12C19 12.5523 18.5523 13 18 13L13 13V18C13 18.5523 12.5523 19 12 19C11.4477 19 11 18.5523 11 18V13L6 13C5.44772 13 5 12.5523 5 12C5 11.4477 5.44771 11 6 11L11 11V6C11 5.44772 11.4477 5 12 5Z"
+      />
+    </Icon>
+  );
+}
diff --git a/src/icon/search.js b/src/icon/search.js
new file mode 100644
index 000000000..eda0589b8
--- /dev/null
+++ b/src/icon/search.js
@@ -0,0 +1,24 @@
+/*
+Copyright (c) 2018 Uber Technologies, Inc.
+
+This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*/
+// @flow
+// BASEUI-GENERATED-REACT-ICON
+// DO NOT EDIT THIS FILE DIRECTLY, SEE README.md
+import * as React from 'react';
+import Icon from './icon';
+import type {IconPropsT} from './types';
+
+export default function Search(props: IconPropsT) {
+  return (
+    <Icon title="Search" viewBox="0 0 24 24" {...props}>
+      <path
+        fillRule="evenodd"
+        clipRule="evenodd"
+        d="M11 6C8.79086 6 7 7.79086 7 10C7 12.2091 8.79086 14 11 14C13.2091 14 15 12.2091 15 10C15 7.79086 13.2091 6 11 6ZM5 10C5 6.68629 7.68629 4 11 4C14.3137 4 17 6.68629 17 10C17 11.2958 16.5892 12.4957 15.8907 13.4765L19.7071 17.2929C20.0976 17.6834 20.0976 18.3166 19.7071 18.7071C19.3166 19.0976 18.6834 19.0976 18.2929 18.7071L14.4765 14.8907C13.4957 15.5892 12.2958 16 11 16C7.68629 16 5 13.3137 5 10Z"
+      />
+    </Icon>
+  );
+}
diff --git a/src/icon/spinner.js b/src/icon/spinner.js
new file mode 100644
index 000000000..78fde7e63
--- /dev/null
+++ b/src/icon/spinner.js
@@ -0,0 +1,30 @@
+/*
+Copyright (c) 2018 Uber Technologies, Inc.
+
+This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*/
+// @flow
+// BASEUI-GENERATED-REACT-ICON
+// DO NOT EDIT THIS FILE DIRECTLY, SEE README.md
+import * as React from 'react';
+import Icon from './icon';
+import type {IconPropsT} from './types';
+
+export default function Spinner(props: IconPropsT) {
+  return (
+    <Icon title="Spinner" viewBox="0 0 24 24" {...props}>
+      <path
+        fillRule="evenodd"
+        clipRule="evenodd"
+        d="M12 5C8.13401 5 5 8.13401 5 12C5 15.866 8.13401 19 12 19C15.866 19 19 15.866 19 12C19 8.13401 15.866 5 12 5ZM3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12Z"
+        fillOpacity="0.32"
+      />
+      <path
+        fillRule="evenodd"
+        clipRule="evenodd"
+        d="M16.9497 7.05015C14.2161 4.31648 9.78392 4.31648 7.05025 7.05015C6.65973 7.44067 6.02656 7.44067 5.63604 7.05015C5.24551 6.65962 5.24551 6.02646 5.63604 5.63593C9.15076 2.12121 14.8492 2.12121 18.364 5.63593C18.7545 6.02646 18.7545 6.65962 18.364 7.05015C17.9734 7.44067 17.3403 7.44067 16.9497 7.05015Z"
+      />
+    </Icon>
+  );
+}
diff --git a/src/icon/stories.js b/src/icon/stories.js
new file mode 100644
index 000000000..59f9f86b4
--- /dev/null
+++ b/src/icon/stories.js
@@ -0,0 +1,21 @@
+/*
+Copyright (c) 2018 Uber Technologies, Inc.
+
+This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*/
+// @flow
+/* global module */
+import {storiesOf} from '@storybook/react';
+import {withReadme} from 'storybook-readme';
+import examples from './examples';
+
+// $FlowFixMe
+import IconReadme from '../../rfcs/icon-component.md';
+
+Object.entries(examples).forEach(([description, example]) =>
+  storiesOf('Icon', module)
+    .addDecorator(withReadme(IconReadme))
+    // $FlowFixMe
+    .add(description, example),
+);
diff --git a/src/icon/styled-components.js b/src/icon/styled-components.js
new file mode 100644
index 000000000..ab52a78a2
--- /dev/null
+++ b/src/icon/styled-components.js
@@ -0,0 +1,30 @@
+/*
+Copyright (c) 2018 Uber Technologies, Inc.
+
+This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*/
+// @flow
+import {styled} from '../styles';
+import type {StyledComponentParamsT} from './types';
+
+export const Svg = styled(
+  'svg',
+  ({$theme, $size, $color}: StyledComponentParamsT) => {
+    if ($size) {
+      if ($theme.sizing.hasOwnProperty($size)) {
+        $size = $theme.sizing[$size];
+      } else if (typeof $size === 'number') {
+        $size = `${$size}px`;
+      }
+    } else {
+      $size = $theme.sizing.scale800;
+    }
+    return {
+      display: 'inline-block',
+      fill: $color || 'currentColor',
+      height: $size,
+      width: $size,
+    };
+  },
+);
diff --git a/src/icon/svg/alert.svg b/src/icon/svg/alert.svg
new file mode 100644
index 000000000..99e5b7406
--- /dev/null
+++ b/src/icon/svg/alert.svg
@@ -0,0 +1,3 @@
+<svg viewBox="0 0 24 24">
+  <path fill-rule="evenodd" clip-rule="evenodd" d="M12 21C16.9706 21 21 16.9706 21 12C21 7.02945 16.9706 3 12 3C7.02942 3 3 7.02945 3 12C3 16.9706 7.02942 21 12 21ZM12 6C12.5523 6 13 6.44772 13 7V13C13 13.5523 12.5523 14 12 14C11.4477 14 11 13.5523 11 13V7C11 6.44772 11.4477 6 12 6ZM13 17C13 17.5523 12.5523 18 12 18C11.4477 18 11 17.5523 11 17C11 16.4477 11.4477 16 12 16C12.5523 16 13 16.4477 13 17Z"/>
+</svg>
\ No newline at end of file
diff --git a/src/icon/svg/arrow-down.svg b/src/icon/svg/arrow-down.svg
new file mode 100644
index 000000000..b29ac5010
--- /dev/null
+++ b/src/icon/svg/arrow-down.svg
@@ -0,0 +1,3 @@
+<svg viewBox="0 0 24 24">
+  <path fill-rule="evenodd" clip-rule="evenodd" d="M12 6C12.5523 6 13 6.44772 13 7V14.5858L15.2929 12.2929C15.6834 11.9024 16.3166 11.9024 16.7071 12.2929C17.0976 12.6834 17.0976 13.3166 16.7071 13.7071L12.7071 17.7071C12.3166 18.0976 11.6834 18.0976 11.2929 17.7071L7.29289 13.7071C6.90237 13.3166 6.90237 12.6834 7.29289 12.2929C7.68342 11.9024 8.31658 11.9024 8.70711 12.2929L11 14.5858V7C11 6.44772 11.4477 6 12 6Z"/>
+</svg>
\ No newline at end of file
diff --git a/src/icon/svg/arrow-left.svg b/src/icon/svg/arrow-left.svg
new file mode 100644
index 000000000..a1ad9b230
--- /dev/null
+++ b/src/icon/svg/arrow-left.svg
@@ -0,0 +1,3 @@
+<svg viewBox="0 0 24 24">
+  <path fill-rule="evenodd" clip-rule="evenodd" d="M6.29289 11.2929C5.90237 11.6834 5.90237 12.3166 6.29289 12.7071L10.2929 16.7071C10.6834 17.0976 11.3166 17.0976 11.7071 16.7071C12.0976 16.3166 12.0976 15.6834 11.7071 15.2929L9.41421 13H17C17.5523 13 18 12.5523 18 12C18 11.4477 17.5523 11 17 11H9.41421L11.7071 8.70711C12.0976 8.31658 12.0976 7.68342 11.7071 7.29289C11.3166 6.90237 10.6834 6.90237 10.2929 7.29289L6.29289 11.2929Z"/>
+</svg>
\ No newline at end of file
diff --git a/src/icon/svg/arrow-right.svg b/src/icon/svg/arrow-right.svg
new file mode 100644
index 000000000..b89c09a84
--- /dev/null
+++ b/src/icon/svg/arrow-right.svg
@@ -0,0 +1,3 @@
+<svg viewBox="0 0 24 24">
+  <path fill-rule="evenodd" clip-rule="evenodd" d="M6 12C6 12.5523 6.44772 13 7 13H14.5858L12.2929 15.2929C11.9024 15.6834 11.9024 16.3166 12.2929 16.7071C12.6834 17.0976 13.3166 17.0976 13.7071 16.7071L17.7071 12.7071C17.8946 12.5196 18 12.2652 18 12C18 11.7348 17.8946 11.4804 17.7071 11.2929L13.7071 7.29289C13.3166 6.90237 12.6834 6.90237 12.2929 7.29289C11.9024 7.68342 11.9024 8.31658 12.2929 8.70711L14.5858 11H7C6.44772 11 6 11.4477 6 12Z"/>
+</svg>
\ No newline at end of file
diff --git a/src/icon/svg/arrow-up.svg b/src/icon/svg/arrow-up.svg
new file mode 100644
index 000000000..9839c8b7f
--- /dev/null
+++ b/src/icon/svg/arrow-up.svg
@@ -0,0 +1,3 @@
+<svg viewBox="0 0 24 24">
+  <path fill-rule="evenodd" clip-rule="evenodd" d="M11.2929 6.29289C11.6834 5.90237 12.3166 5.90237 12.7071 6.29289L16.7071 10.2929C17.0976 10.6834 17.0976 11.3166 16.7071 11.7071C16.3166 12.0976 15.6834 12.0976 15.2929 11.7071L13 9.41421V17C13 17.5523 12.5523 18 12 18C11.4477 18 11 17.5523 11 17V9.41421L8.70711 11.7071C8.31658 12.0976 7.68342 12.0976 7.29289 11.7071C6.90237 11.3166 6.90237 10.6834 7.29289 10.2929L11.2929 6.29289Z"/>
+</svg>
\ No newline at end of file
diff --git a/src/icon/svg/check-indeterminate.svg b/src/icon/svg/check-indeterminate.svg
new file mode 100644
index 000000000..baf440bee
--- /dev/null
+++ b/src/icon/svg/check-indeterminate.svg
@@ -0,0 +1,3 @@
+<svg viewBox="0 0 24 24">
+  <path fill-rule="evenodd" clip-rule="evenodd" d="M6 12C6 11.4477 6.44772 11 7 11H17C17.5523 11 18 11.4477 18 12C18 12.5523 17.5523 13 17 13H7C6.44772 13 6 12.5523 6 12Z"/>
+</svg>
\ No newline at end of file
diff --git a/src/icon/svg/check.svg b/src/icon/svg/check.svg
new file mode 100644
index 000000000..67918e49a
--- /dev/null
+++ b/src/icon/svg/check.svg
@@ -0,0 +1,3 @@
+<svg viewBox="0 0 24 24">
+  <path fill-rule="evenodd" clip-rule="evenodd" d="M17.6 7.20006C18.0418 7.53143 18.1314 8.15823 17.8 8.60006L11.8 16.6001C11.6261 16.832 11.3601 16.977 11.0709 16.9975C10.7817 17.0181 10.4979 16.9122 10.2929 16.7072L7.29289 13.7072C6.90237 13.3166 6.90237 12.6835 7.29289 12.293C7.68342 11.9024 8.31658 11.9024 8.70711 12.293L10.8918 14.4777L16.2 7.40006C16.5314 6.95823 17.1582 6.86869 17.6 7.20006Z"/>
+</svg>
diff --git a/src/icon/svg/chevron-left.svg b/src/icon/svg/chevron-left.svg
new file mode 100644
index 000000000..85af824d2
--- /dev/null
+++ b/src/icon/svg/chevron-left.svg
@@ -0,0 +1,3 @@
+<svg viewBox="0 0 24 24">
+  <path fill-rule="evenodd" clip-rule="evenodd" d="M9 12C9 12.2652 9.10536 12.5196 9.29289 12.7071L13.2929 16.7071C13.6834 17.0976 14.3166 17.0976 14.7071 16.7071C15.0976 16.3166 15.0976 15.6834 14.7071 15.2929L11.4142 12L14.7071 8.70711C15.0976 8.31658 15.0976 7.68342 14.7071 7.29289C14.3166 6.90237 13.6834 6.90237 13.2929 7.29289L9.29289 11.2929C9.10536 11.4804 9 11.7348 9 12Z"/>
+</svg>
diff --git a/src/icon/svg/chevron-right.svg b/src/icon/svg/chevron-right.svg
new file mode 100644
index 000000000..2d9ff08fa
--- /dev/null
+++ b/src/icon/svg/chevron-right.svg
@@ -0,0 +1,3 @@
+<svg viewBox="0 0 24 24">
+  <path fill-rule="evenodd" clip-rule="evenodd" d="M9.29289 7.29289C8.90237 7.68342 8.90237 8.31658 9.29289 8.70711L12.5858 12L9.29289 15.2929C8.90237 15.6834 8.90237 16.3166 9.29289 16.7071C9.68342 17.0976 10.3166 17.0976 10.7071 16.7071L14.7071 12.7071C14.8946 12.5196 15 12.2652 15 12C15 11.7348 14.8946 11.4804 14.7071 11.2929L10.7071 7.29289C10.3166 6.90237 9.68342 6.90237 9.29289 7.29289Z"/>
+</svg>
\ No newline at end of file
diff --git a/src/icon/svg/delete-alt.svg b/src/icon/svg/delete-alt.svg
new file mode 100644
index 000000000..650d13295
--- /dev/null
+++ b/src/icon/svg/delete-alt.svg
@@ -0,0 +1,3 @@
+<svg viewBox="0 0 24 24">
+  <path fill-rule="evenodd" clip-rule="evenodd" d="M12 20C16.4183 20 20 16.4183 20 12C20 7.58173 16.4183 4 12 4C7.58173 4 4 7.58173 4 12C4 16.4183 7.58173 20 12 20ZM10.0303 8.96967C9.73743 8.67679 9.26257 8.67679 8.96967 8.96967C8.67676 9.26257 8.67676 9.73743 8.96967 10.0303L10.9393 12L8.96967 13.9697C8.67676 14.2626 8.67676 14.7374 8.96967 15.0303C9.26257 15.3232 9.73743 15.3232 10.0303 15.0303L12 13.0607L13.9697 15.0303C14.2626 15.3232 14.7374 15.3232 15.0303 15.0303C15.3232 14.7374 15.3232 14.2626 15.0303 13.9697L13.0607 12L15.0303 10.0303C15.3232 9.73743 15.3232 9.26257 15.0303 8.96967C14.7374 8.67679 14.2626 8.67679 13.9697 8.96967L12 10.9393L10.0303 8.96967Z"/>
+</svg>
\ No newline at end of file
diff --git a/src/icon/svg/delete.svg b/src/icon/svg/delete.svg
new file mode 100644
index 000000000..5395c8ae5
--- /dev/null
+++ b/src/icon/svg/delete.svg
@@ -0,0 +1,3 @@
+<svg viewBox="0 0 24 24">
+  <path fill-rule="evenodd" clip-rule="evenodd" d="M7.29289 7.29289C7.68342 6.90237 8.31658 6.90237 8.70711 7.29289L12 10.5858L15.2929 7.29289C15.6834 6.90237 16.3166 6.90237 16.7071 7.29289C17.0976 7.68342 17.0976 8.31658 16.7071 8.70711L13.4142 12L16.7071 15.2929C17.0976 15.6834 17.0976 16.3166 16.7071 16.7071C16.3166 17.0976 15.6834 17.0976 15.2929 16.7071L12 13.4142L8.70711 16.7071C8.31658 17.0976 7.68342 17.0976 7.29289 16.7071C6.90237 16.3166 6.90237 15.6834 7.29289 15.2929L10.5858 12L7.29289 8.70711C6.90237 8.31658 6.90237 7.68342 7.29289 7.29289Z"/>
+</svg>
\ No newline at end of file
diff --git a/src/icon/svg/filter.svg b/src/icon/svg/filter.svg
new file mode 100644
index 000000000..277e0a1b8
--- /dev/null
+++ b/src/icon/svg/filter.svg
@@ -0,0 +1,5 @@
+<svg viewBox="0 0 24 24">
+  <rect x="7" y="11" width="10" height="2" rx="1"/>
+  <rect x="4" y="7" width="16" height="2" rx="1"/>
+  <rect x="10" y="15" width="4" height="2" rx="1"/>
+</svg>
\ No newline at end of file
diff --git a/src/icon/svg/grab.svg b/src/icon/svg/grab.svg
new file mode 100644
index 000000000..0ab29d40b
--- /dev/null
+++ b/src/icon/svg/grab.svg
@@ -0,0 +1,3 @@
+<svg viewBox="0 0 24 24">
+  <path fill-rule="evenodd" clip-rule="evenodd" d="M5 8C4.44775 8 4 8.44775 4 9C4 9.55225 4.44775 10 5 10H19C19.5522 10 20 9.55225 20 9C20 8.44775 19.5522 8 19 8H5ZM5 14C4.44775 14 4 14.4478 4 15C4 15.5522 4.44775 16 5 16H19C19.5522 16 20 15.5522 20 15C20 14.4478 19.5522 14 19 14H5Z"/>
+</svg>
\ No newline at end of file
diff --git a/src/icon/svg/menu.svg b/src/icon/svg/menu.svg
new file mode 100644
index 000000000..55330ddeb
--- /dev/null
+++ b/src/icon/svg/menu.svg
@@ -0,0 +1,5 @@
+<svg viewBox="0 0 24 24">
+  <rect x="4" y="11" width="16" height="2" rx="1"/>
+  <rect x="4" y="5" width="16" height="2" rx="1"/>
+  <rect x="4" y="17" width="16" height="2" rx="1"/>
+</svg>
\ No newline at end of file
diff --git a/src/icon/svg/overflow.svg b/src/icon/svg/overflow.svg
new file mode 100644
index 000000000..c74d96571
--- /dev/null
+++ b/src/icon/svg/overflow.svg
@@ -0,0 +1,5 @@
+<svg viewBox="0 0 24 24">
+  <circle cx="6" cy="12" r="2"/>
+  <circle cx="12" cy="12" r="2"/>
+  <circle cx="18" cy="12" r="2"/>
+</svg>
\ No newline at end of file
diff --git a/src/icon/svg/plus.svg b/src/icon/svg/plus.svg
new file mode 100644
index 000000000..3b2459683
--- /dev/null
+++ b/src/icon/svg/plus.svg
@@ -0,0 +1,3 @@
+<svg viewBox="0 0 24 24">
+  <path fill-rule="evenodd" clip-rule="evenodd" d="M12 5C12.5523 5 13 5.44772 13 6V11L18 11C18.5523 11 19 11.4477 19 12C19 12.5523 18.5523 13 18 13L13 13V18C13 18.5523 12.5523 19 12 19C11.4477 19 11 18.5523 11 18V13L6 13C5.44772 13 5 12.5523 5 12C5 11.4477 5.44771 11 6 11L11 11V6C11 5.44772 11.4477 5 12 5Z"/>
+</svg>
\ No newline at end of file
diff --git a/src/icon/svg/search.svg b/src/icon/svg/search.svg
new file mode 100644
index 000000000..0f38943a4
--- /dev/null
+++ b/src/icon/svg/search.svg
@@ -0,0 +1,3 @@
+<svg viewBox="0 0 24 24">
+  <path fill-rule="evenodd" clip-rule="evenodd" d="M11 6C8.79086 6 7 7.79086 7 10C7 12.2091 8.79086 14 11 14C13.2091 14 15 12.2091 15 10C15 7.79086 13.2091 6 11 6ZM5 10C5 6.68629 7.68629 4 11 4C14.3137 4 17 6.68629 17 10C17 11.2958 16.5892 12.4957 15.8907 13.4765L19.7071 17.2929C20.0976 17.6834 20.0976 18.3166 19.7071 18.7071C19.3166 19.0976 18.6834 19.0976 18.2929 18.7071L14.4765 14.8907C13.4957 15.5892 12.2958 16 11 16C7.68629 16 5 13.3137 5 10Z"/>
+</svg>
diff --git a/src/icon/svg/spinner.svg b/src/icon/svg/spinner.svg
new file mode 100644
index 000000000..8825cdaa3
--- /dev/null
+++ b/src/icon/svg/spinner.svg
@@ -0,0 +1,4 @@
+<svg viewBox="0 0 24 24">
+  <path fill-rule="evenodd" clip-rule="evenodd" d="M12 5C8.13401 5 5 8.13401 5 12C5 15.866 8.13401 19 12 19C15.866 19 19 15.866 19 12C19 8.13401 15.866 5 12 5ZM3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12Z" fill-opacity="0.32"/>
+  <path fill-rule="evenodd" clip-rule="evenodd" d="M16.9497 7.05015C14.2161 4.31648 9.78392 4.31648 7.05025 7.05015C6.65973 7.44067 6.02656 7.44067 5.63604 7.05015C5.24551 6.65962 5.24551 6.02646 5.63604 5.63593C9.15076 2.12121 14.8492 2.12121 18.364 5.63593C18.7545 6.02646 18.7545 6.65962 18.364 7.05015C17.9734 7.44067 17.3403 7.44067 16.9497 7.05015Z"/>
+</svg>
\ No newline at end of file
diff --git a/src/icon/svg/triangle-down.svg b/src/icon/svg/triangle-down.svg
new file mode 100644
index 000000000..ad5a7d3c0
--- /dev/null
+++ b/src/icon/svg/triangle-down.svg
@@ -0,0 +1,3 @@
+<svg viewBox="0 0 24 24">
+  <path d="M12.7071 15.2929L17.1464 10.8536C17.4614 10.5386 17.2383 10 16.7929 10L7.20711 10C6.76165 10 6.53857 10.5386 6.85355 10.8536L11.2929 15.2929C11.6834 15.6834 12.3166 15.6834 12.7071 15.2929Z"/>
+</svg>
\ No newline at end of file
diff --git a/src/icon/svg/triangle-left.svg b/src/icon/svg/triangle-left.svg
new file mode 100644
index 000000000..cd8e47159
--- /dev/null
+++ b/src/icon/svg/triangle-left.svg
@@ -0,0 +1,3 @@
+<svg viewBox="0 0 24 24">
+  <path d="M8.70711 11.2929L13.1464 6.85355C13.4614 6.53857 14 6.76165 14 7.20711L14 16.7929C14 17.2383 13.4614 17.4614 13.1464 17.1464L8.70711 12.7071C8.31658 12.3166 8.31658 11.6834 8.70711 11.2929Z"/>
+</svg>
\ No newline at end of file
diff --git a/src/icon/svg/triangle-right.svg b/src/icon/svg/triangle-right.svg
new file mode 100644
index 000000000..a52e44b41
--- /dev/null
+++ b/src/icon/svg/triangle-right.svg
@@ -0,0 +1,3 @@
+<svg viewBox="0 0 24 24">
+  <path d="M15.2929 11.2929L10.8536 6.85355C10.5386 6.53857 10 6.76165 10 7.20711L10 16.7929C10 17.2383 10.5386 17.4614 10.8536 17.1464L15.2929 12.7071C15.6834 12.3166 15.6834 11.6834 15.2929 11.2929Z"/>
+</svg>
\ No newline at end of file
diff --git a/src/icon/svg/triangle-up.svg b/src/icon/svg/triangle-up.svg
new file mode 100644
index 000000000..a90f91bef
--- /dev/null
+++ b/src/icon/svg/triangle-up.svg
@@ -0,0 +1,3 @@
+<svg viewBox="0 0 24 24">
+  <path d="M12.7071 8.70711L17.1464 13.1464C17.4614 13.4614 17.2383 14 16.7929 14L7.20711 14C6.76165 14 6.53857 13.4614 6.85355 13.1464L11.2929 8.70711C11.6834 8.31658 12.3166 8.31658 12.7071 8.70711Z"/>
+</svg>
\ No newline at end of file
diff --git a/src/icon/svg/upload.svg b/src/icon/svg/upload.svg
new file mode 100644
index 000000000..e556a29ea
--- /dev/null
+++ b/src/icon/svg/upload.svg
@@ -0,0 +1,3 @@
+<svg viewBox="0 0 24 24">
+  <path fill-rule="evenodd" clip-rule="evenodd" d="M14.5 5C12.8755 5 11.4519 5.86084 10.6609 7.15112C10.2905 7.05249 9.90137 7 9.5 7C7.14185 7 5.20752 8.81372 5.01562 11.1221C3.28247 11.5605 2 13.1304 2 15C2 17.2092 3.79077 19 6 19H11V14.4143L9.70703 15.707C9.31665 16.0977 8.68335 16.0977 8.29297 15.707C7.90234 15.3167 7.90234 14.6833 8.29297 14.293L11.293 11.293C11.6833 10.9023 12.3167 10.9023 12.707 11.293L15.707 14.293C16.0977 14.6833 16.0977 15.3167 15.707 15.707C15.3167 16.0977 14.6833 16.0977 14.293 15.707L13 14.4143V19H17C19.7615 19 22 16.7615 22 14C22 11.9492 20.7656 10.187 18.9993 9.41577C18.9543 6.96924 16.9573 5 14.5 5Z"/>
+</svg>
\ No newline at end of file
diff --git a/src/icon/triangle-down.js b/src/icon/triangle-down.js
new file mode 100644
index 000000000..ad4f6c21e
--- /dev/null
+++ b/src/icon/triangle-down.js
@@ -0,0 +1,20 @@
+/*
+Copyright (c) 2018 Uber Technologies, Inc.
+
+This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*/
+// @flow
+// BASEUI-GENERATED-REACT-ICON
+// DO NOT EDIT THIS FILE DIRECTLY, SEE README.md
+import * as React from 'react';
+import Icon from './icon';
+import type {IconPropsT} from './types';
+
+export default function TriangleDown(props: IconPropsT) {
+  return (
+    <Icon title="Triangle Down" viewBox="0 0 24 24" {...props}>
+      <path d="M12.7071 15.2929L17.1464 10.8536C17.4614 10.5386 17.2383 10 16.7929 10L7.20711 10C6.76165 10 6.53857 10.5386 6.85355 10.8536L11.2929 15.2929C11.6834 15.6834 12.3166 15.6834 12.7071 15.2929Z" />
+    </Icon>
+  );
+}
diff --git a/src/icon/triangle-left.js b/src/icon/triangle-left.js
new file mode 100644
index 000000000..b10347330
--- /dev/null
+++ b/src/icon/triangle-left.js
@@ -0,0 +1,20 @@
+/*
+Copyright (c) 2018 Uber Technologies, Inc.
+
+This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*/
+// @flow
+// BASEUI-GENERATED-REACT-ICON
+// DO NOT EDIT THIS FILE DIRECTLY, SEE README.md
+import * as React from 'react';
+import Icon from './icon';
+import type {IconPropsT} from './types';
+
+export default function TriangleLeft(props: IconPropsT) {
+  return (
+    <Icon title="Triangle Left" viewBox="0 0 24 24" {...props}>
+      <path d="M8.70711 11.2929L13.1464 6.85355C13.4614 6.53857 14 6.76165 14 7.20711L14 16.7929C14 17.2383 13.4614 17.4614 13.1464 17.1464L8.70711 12.7071C8.31658 12.3166 8.31658 11.6834 8.70711 11.2929Z" />
+    </Icon>
+  );
+}
diff --git a/src/icon/triangle-right.js b/src/icon/triangle-right.js
new file mode 100644
index 000000000..610ed806b
--- /dev/null
+++ b/src/icon/triangle-right.js
@@ -0,0 +1,20 @@
+/*
+Copyright (c) 2018 Uber Technologies, Inc.
+
+This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*/
+// @flow
+// BASEUI-GENERATED-REACT-ICON
+// DO NOT EDIT THIS FILE DIRECTLY, SEE README.md
+import * as React from 'react';
+import Icon from './icon';
+import type {IconPropsT} from './types';
+
+export default function TriangleRight(props: IconPropsT) {
+  return (
+    <Icon title="Triangle Right" viewBox="0 0 24 24" {...props}>
+      <path d="M15.2929 11.2929L10.8536 6.85355C10.5386 6.53857 10 6.76165 10 7.20711L10 16.7929C10 17.2383 10.5386 17.4614 10.8536 17.1464L15.2929 12.7071C15.6834 12.3166 15.6834 11.6834 15.2929 11.2929Z" />
+    </Icon>
+  );
+}
diff --git a/src/icon/triangle-up.js b/src/icon/triangle-up.js
new file mode 100644
index 000000000..ab985ed49
--- /dev/null
+++ b/src/icon/triangle-up.js
@@ -0,0 +1,20 @@
+/*
+Copyright (c) 2018 Uber Technologies, Inc.
+
+This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*/
+// @flow
+// BASEUI-GENERATED-REACT-ICON
+// DO NOT EDIT THIS FILE DIRECTLY, SEE README.md
+import * as React from 'react';
+import Icon from './icon';
+import type {IconPropsT} from './types';
+
+export default function TriangleUp(props: IconPropsT) {
+  return (
+    <Icon title="Triangle Up" viewBox="0 0 24 24" {...props}>
+      <path d="M12.7071 8.70711L17.1464 13.1464C17.4614 13.4614 17.2383 14 16.7929 14L7.20711 14C6.76165 14 6.53857 13.4614 6.85355 13.1464L11.2929 8.70711C11.6834 8.31658 12.3166 8.31658 12.7071 8.70711Z" />
+    </Icon>
+  );
+}
diff --git a/src/icon/types.js b/src/icon/types.js
new file mode 100644
index 000000000..a6861cffd
--- /dev/null
+++ b/src/icon/types.js
@@ -0,0 +1,40 @@
+/*
+Copyright (c) 2018 Uber Technologies, Inc.
+
+This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*/
+// @flow
+/* eslint-disable flowtype/generic-spacing */
+import * as React from 'react';
+import type {ThemeT} from '../styles/types';
+import type {OverrideT} from '../helpers/overrides';
+
+export type OverridesT = {
+  Svg?: OverrideT<StyledComponentArgsT>,
+};
+
+export type SizeT = number | string;
+export type ColorT = string;
+
+export type StyledComponentArgsT = {
+  $size?: SizeT,
+  $color?: ColorT,
+  // Styletron stuff
+  $as?: string,
+  // styled function wrapper related
+  $style?: ?{},
+  $ref?: React.Ref<*>,
+};
+
+export type StyledComponentParamsT = StyledComponentArgsT & {
+  $theme: ThemeT,
+};
+
+export type IconPropsT = {
+  children?: React.Node,
+  size?: SizeT,
+  color?: ColorT,
+  title?: string,
+  overrides?: OverridesT,
+};
diff --git a/src/icon/upload.js b/src/icon/upload.js
new file mode 100644
index 000000000..092a06218
--- /dev/null
+++ b/src/icon/upload.js
@@ -0,0 +1,24 @@
+/*
+Copyright (c) 2018 Uber Technologies, Inc.
+
+This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*/
+// @flow
+// BASEUI-GENERATED-REACT-ICON
+// DO NOT EDIT THIS FILE DIRECTLY, SEE README.md
+import * as React from 'react';
+import Icon from './icon';
+import type {IconPropsT} from './types';
+
+export default function Upload(props: IconPropsT) {
+  return (
+    <Icon title="Upload" viewBox="0 0 24 24" {...props}>
+      <path
+        fillRule="evenodd"
+        clipRule="evenodd"
+        d="M14.5 5C12.8755 5 11.4519 5.86084 10.6609 7.15112C10.2905 7.05249 9.90137 7 9.5 7C7.14185 7 5.20752 8.81372 5.01562 11.1221C3.28247 11.5605 2 13.1304 2 15C2 17.2092 3.79077 19 6 19H11V14.4143L9.70703 15.707C9.31665 16.0977 8.68335 16.0977 8.29297 15.707C7.90234 15.3167 7.90234 14.6833 8.29297 14.293L11.293 11.293C11.6833 10.9023 12.3167 10.9023 12.707 11.293L15.707 14.293C16.0977 14.6833 16.0977 15.3167 15.707 15.707C15.3167 16.0977 14.6833 16.0977 14.293 15.707L13 14.4143V19H17C19.7615 19 22 16.7615 22 14C22 11.9492 20.7656 10.187 18.9993 9.41577C18.9543 6.96924 16.9573 5 14.5 5Z"
+      />
+    </Icon>
+  );
+}


Test patch:
diff --git a/src/icon/__tests__/__snapshots__/icon.test.js.snap b/src/icon/__tests__/__snapshots__/icon.test.js.snap
new file mode 100644
index 000000000..4df1e7752
--- /dev/null
+++ b/src/icon/__tests__/__snapshots__/icon.test.js.snap
@@ -0,0 +1,16 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Icon renders an icon with viewbox and title: Icon basic render 1`] = `
+<MockStyledComponent
+  viewBox="0 0 23px 23px"
+>
+  <title>
+    Test
+  </title>
+  <path
+    clipRule="evenodd"
+    d="M6 12C6 11.4477 6.44772 11 7 11H17C17.5523 11 18 11.4477 18 12C18 12.5523 17.5523 13 17 13H7C6.44772 13 6 12.5523 6 12Z"
+    fillRule="evenodd"
+  />
+</MockStyledComponent>
+`;
diff --git a/src/icon/__tests__/__snapshots__/styled-components.test.js.snap b/src/icon/__tests__/__snapshots__/styled-components.test.js.snap
new file mode 100644
index 000000000..5d8957b12
--- /dev/null
+++ b/src/icon/__tests__/__snapshots__/styled-components.test.js.snap
@@ -0,0 +1,10 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Icon styled components Svg has correct default styles: Svg basic render 1`] = `
+Object {
+  "display": "inline-block",
+  "fill": "currentColor",
+  "height": "$theme.sizing.scale800",
+  "width": "$theme.sizing.scale800",
+}
+`;
diff --git a/src/icon/__tests__/icon.test.js b/src/icon/__tests__/icon.test.js
new file mode 100644
index 000000000..d06901065
--- /dev/null
+++ b/src/icon/__tests__/icon.test.js
@@ -0,0 +1,53 @@
+/*
+Copyright (c) 2018 Uber Technologies, Inc.
+
+This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*/
+// @flow
+/* eslint-env browser */
+
+import React from 'react';
+import {shallow} from 'enzyme';
+import {Icon} from '../index';
+import {Svg} from '../styled-components';
+import * as Icons from '../icon-exports';
+
+describe('Icon', () => {
+  test('renders an icon with viewbox and title', () => {
+    const wrapper = shallow(
+      <Icon viewBox="0 0 23px 23px" title="Test">
+        <path
+          fillRule="evenodd"
+          clipRule="evenodd"
+          d="M6 12C6 11.4477 6.44772 11 7 11H17C17.5523 11 18 11.4477 18 12C18 12.5523 17.5523 13 17 13H7C6.44772 13 6 12.5523 6 12Z"
+        />
+      </Icon>,
+    );
+
+    expect(wrapper).toMatchSnapshot('Icon basic render');
+  });
+
+  test('supports overrides', () => {
+    const wrapper = shallow(
+      <Icon overrides={{Svg: {style: {fill: 'purple'}}}}>
+        <path
+          fillRule="evenodd"
+          clipRule="evenodd"
+          d="M6 12C6 11.4477 6.44772 11 7 11H17C17.5523 11 18 11.4477 18 12C18 12.5523 17.5523 13 17 13H7C6.44772 13 6 12.5523 6 12Z"
+        />
+      </Icon>,
+    );
+
+    expect(wrapper.find(Svg).prop('$style')).toEqual({fill: 'purple'});
+  });
+
+  // Test that all the icons render
+  Object.keys(Icons).forEach(key => {
+    const Component = Icons[key];
+    test(`renders ${key} icon`, () => {
+      const wrapper = shallow(<Component />);
+      expect(wrapper).toExist();
+    });
+  });
+});
diff --git a/src/icon/__tests__/styled-components.test.js b/src/icon/__tests__/styled-components.test.js
new file mode 100644
index 000000000..2930b963c
--- /dev/null
+++ b/src/icon/__tests__/styled-components.test.js
@@ -0,0 +1,31 @@
+/*
+Copyright (c) 2018 Uber Technologies, Inc.
+
+This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*/
+// @flow
+
+import React from 'react';
+import {shallow} from 'enzyme';
+import {Svg} from '../styled-components';
+
+describe('Icon styled components', () => {
+  test('Svg has correct default styles', () => {
+    const wrapper = shallow(<Svg />);
+
+    expect(wrapper.instance().getStyles()).toMatchSnapshot('Svg basic render');
+  });
+
+  test('Svg handles color override', () => {
+    const wrapper = shallow(<Svg $color="purple" />);
+    expect(wrapper.instance().getStyles()).toHaveProperty('fill', 'purple');
+  });
+
+  test('Svg handles size via theme constant', () => {
+    const wrapper = shallow(<Svg $size="scale400" />);
+    const styles = wrapper.instance().getStyles();
+    expect(styles).toHaveProperty('width', '$theme.sizing.scale400');
+    expect(styles).toHaveProperty('height', '$theme.sizing.scale400');
+  });
+});