Repository: mapbox/mr-ui (ts)

Issue:
Rewrite icon-text component
### Criteria:

- TypeScript
- Functional component
- _possible_ radix inner workings or adoption of components re-written with radix like icon and control-label

Pull request description:
Rewrite icon-text
Simple changes to the icon-text component to use TypeScript, and React testing library. **Note** that I removed the `gap` which was not actually being used but documented as an option.

---

Closes #190 

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c0b8d01..572066d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,7 @@ Changelog
 ---
 
 ## HEAD
+- [fix] `gap` prop in `src/components/icon-text` which was not in use.
 - [breaking] Deletes `src/components/tab-list`
   - tab-list component was not used anywhere according to our audit and radix does not have support for such mobile functionality (such as displaying a popover for the rest of the tabs that do not fit on mobile)
 - [breaking] Deletes `src/components/underline-tabs`
diff --git a/package-lock.json b/package-lock.json
index 419e629..42147d9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -14,6 +14,7 @@
         "@radix-ui/react-accessible-icon": "^0.1.4",
         "@radix-ui/react-accordion": "^0.1.6",
         "@radix-ui/react-dialog": "^0.1.7",
+        "@radix-ui/react-label": "^1.0.0",
         "@radix-ui/react-switch": "^0.1.5",
         "@radix-ui/react-tabs": "^0.1.5",
         "@radix-ui/react-tooltip": "^0.1.7",
@@ -4066,18 +4067,89 @@
       }
     },
     "node_modules/@radix-ui/react-label": {
-      "version": "0.1.5",
-      "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-0.1.5.tgz",
-      "integrity": "sha512-Au9+n4/DhvjR0IHhvZ1LPdx/OW+3CGDie30ZyCkbSHIuLp4/CV4oPPGBwJ1vY99Jog3zyQhsGww9MXj8O9Aj/A==",
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-1.0.0.tgz",
+      "integrity": "sha512-k+EbxeRaVbSJ4oaR9eUYuC0cDIGRB4TAPhilbFCIMpP9pXFNcyQPQUvRaVOQBrviuArYM80xh0BQR/0y3kjUdQ==",
       "dependencies": {
         "@babel/runtime": "^7.13.10",
-        "@radix-ui/react-compose-refs": "0.1.0",
-        "@radix-ui/react-context": "0.1.1",
-        "@radix-ui/react-id": "0.1.5",
-        "@radix-ui/react-primitive": "0.1.4"
+        "@radix-ui/react-compose-refs": "1.0.0",
+        "@radix-ui/react-context": "1.0.0",
+        "@radix-ui/react-id": "1.0.0",
+        "@radix-ui/react-primitive": "1.0.0"
       },
       "peerDependencies": {
-        "react": "^16.8 || ^17.0"
+        "react": "^16.8 || ^17.0 || ^18.0",
+        "react-dom": "^16.8 || ^17.0 || ^18.0"
+      }
+    },
+    "node_modules/@radix-ui/react-label/node_modules/@radix-ui/react-compose-refs": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.0.tgz",
+      "integrity": "sha512-0KaSv6sx787/hK3eF53iOkiSLwAGlFMx5lotrqD2pTjB18KbybKoEIgkNZTKC60YECDQTKGTRcDBILwZVqVKvA==",
+      "dependencies": {
+        "@babel/runtime": "^7.13.10"
+      },
+      "peerDependencies": {
+        "react": "^16.8 || ^17.0 || ^18.0"
+      }
+    },
+    "node_modules/@radix-ui/react-label/node_modules/@radix-ui/react-context": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.0.0.tgz",
+      "integrity": "sha512-1pVM9RfOQ+n/N5PJK33kRSKsr1glNxomxONs5c49MliinBY6Yw2Q995qfBUUo0/Mbg05B/sGA0gkgPI7kmSHBg==",
+      "dependencies": {
+        "@babel/runtime": "^7.13.10"
+      },
+      "peerDependencies": {
+        "react": "^16.8 || ^17.0 || ^18.0"
+      }
+    },
+    "node_modules/@radix-ui/react-label/node_modules/@radix-ui/react-id": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.0.0.tgz",
+      "integrity": "sha512-Q6iAB/U7Tq3NTolBBQbHTgclPmGWE3OlktGGqrClPozSw4vkQ1DfQAOtzgRPecKsMdJINE05iaoDUG8tRzCBjw==",
+      "dependencies": {
+        "@babel/runtime": "^7.13.10",
+        "@radix-ui/react-use-layout-effect": "1.0.0"
+      },
+      "peerDependencies": {
+        "react": "^16.8 || ^17.0 || ^18.0"
+      }
+    },
+    "node_modules/@radix-ui/react-label/node_modules/@radix-ui/react-primitive": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-1.0.0.tgz",
+      "integrity": "sha512-EyXe6mnRlHZ8b6f4ilTDrXmkLShICIuOTTj0GX4w1rp+wSxf3+TD05u1UOITC8VsJ2a9nwHvdXtOXEOl0Cw/zQ==",
+      "dependencies": {
+        "@babel/runtime": "^7.13.10",
+        "@radix-ui/react-slot": "1.0.0"
+      },
+      "peerDependencies": {
+        "react": "^16.8 || ^17.0 || ^18.0",
+        "react-dom": "^16.8 || ^17.0 || ^18.0"
+      }
+    },
+    "node_modules/@radix-ui/react-label/node_modules/@radix-ui/react-slot": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.0.tgz",
+      "integrity": "sha512-3mrKauI/tWXo1Ll+gN5dHcxDPdm/Df1ufcDLCecn+pnCIVcdWE7CujXo8QaXOWRJyZyQWWbpB8eFwHzWXlv5mQ==",
+      "dependencies": {
+        "@babel/runtime": "^7.13.10",
+        "@radix-ui/react-compose-refs": "1.0.0"
+      },
+      "peerDependencies": {
+        "react": "^16.8 || ^17.0 || ^18.0"
+      }
+    },
+    "node_modules/@radix-ui/react-label/node_modules/@radix-ui/react-use-layout-effect": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.0.tgz",
+      "integrity": "sha512-6Tpkq+R6LOlmQb1R5NNETLG0B4YP0wc+klfXafpUCj6JGyaUc8il7/kUZ7m59rGbXGczE9Bs+iz2qloqsZBduQ==",
+      "dependencies": {
+        "@babel/runtime": "^7.13.10"
+      },
+      "peerDependencies": {
+        "react": "^16.8 || ^17.0 || ^18.0"
       }
     },
     "node_modules/@radix-ui/react-popper": {
@@ -4186,6 +4258,21 @@
         "react": "^16.8 || ^17.0"
       }
     },
+    "node_modules/@radix-ui/react-switch/node_modules/@radix-ui/react-label": {
+      "version": "0.1.5",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-0.1.5.tgz",
+      "integrity": "sha512-Au9+n4/DhvjR0IHhvZ1LPdx/OW+3CGDie30ZyCkbSHIuLp4/CV4oPPGBwJ1vY99Jog3zyQhsGww9MXj8O9Aj/A==",
+      "dependencies": {
+        "@babel/runtime": "^7.13.10",
+        "@radix-ui/react-compose-refs": "0.1.0",
+        "@radix-ui/react-context": "0.1.1",
+        "@radix-ui/react-id": "0.1.5",
+        "@radix-ui/react-primitive": "0.1.4"
+      },
+      "peerDependencies": {
+        "react": "^16.8 || ^17.0"
+      }
+    },
     "node_modules/@radix-ui/react-tabs": {
       "version": "0.1.5",
       "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-0.1.5.tgz",
@@ -28218,15 +28305,68 @@
       }
     },
     "@radix-ui/react-label": {
-      "version": "0.1.5",
-      "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-0.1.5.tgz",
-      "integrity": "sha512-Au9+n4/DhvjR0IHhvZ1LPdx/OW+3CGDie30ZyCkbSHIuLp4/CV4oPPGBwJ1vY99Jog3zyQhsGww9MXj8O9Aj/A==",
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-1.0.0.tgz",
+      "integrity": "sha512-k+EbxeRaVbSJ4oaR9eUYuC0cDIGRB4TAPhilbFCIMpP9pXFNcyQPQUvRaVOQBrviuArYM80xh0BQR/0y3kjUdQ==",
       "requires": {
         "@babel/runtime": "^7.13.10",
-        "@radix-ui/react-compose-refs": "0.1.0",
-        "@radix-ui/react-context": "0.1.1",
-        "@radix-ui/react-id": "0.1.5",
-        "@radix-ui/react-primitive": "0.1.4"
+        "@radix-ui/react-compose-refs": "1.0.0",
+        "@radix-ui/react-context": "1.0.0",
+        "@radix-ui/react-id": "1.0.0",
+        "@radix-ui/react-primitive": "1.0.0"
+      },
+      "dependencies": {
+        "@radix-ui/react-compose-refs": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.0.tgz",
+          "integrity": "sha512-0KaSv6sx787/hK3eF53iOkiSLwAGlFMx5lotrqD2pTjB18KbybKoEIgkNZTKC60YECDQTKGTRcDBILwZVqVKvA==",
+          "requires": {
+            "@babel/runtime": "^7.13.10"
+          }
+        },
+        "@radix-ui/react-context": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.0.0.tgz",
+          "integrity": "sha512-1pVM9RfOQ+n/N5PJK33kRSKsr1glNxomxONs5c49MliinBY6Yw2Q995qfBUUo0/Mbg05B/sGA0gkgPI7kmSHBg==",
+          "requires": {
+            "@babel/runtime": "^7.13.10"
+          }
+        },
+        "@radix-ui/react-id": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.0.0.tgz",
+          "integrity": "sha512-Q6iAB/U7Tq3NTolBBQbHTgclPmGWE3OlktGGqrClPozSw4vkQ1DfQAOtzgRPecKsMdJINE05iaoDUG8tRzCBjw==",
+          "requires": {
+            "@babel/runtime": "^7.13.10",
+            "@radix-ui/react-use-layout-effect": "1.0.0"
+          }
+        },
+        "@radix-ui/react-primitive": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-1.0.0.tgz",
+          "integrity": "sha512-EyXe6mnRlHZ8b6f4ilTDrXmkLShICIuOTTj0GX4w1rp+wSxf3+TD05u1UOITC8VsJ2a9nwHvdXtOXEOl0Cw/zQ==",
+          "requires": {
+            "@babel/runtime": "^7.13.10",
+            "@radix-ui/react-slot": "1.0.0"
+          }
+        },
+        "@radix-ui/react-slot": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.0.tgz",
+          "integrity": "sha512-3mrKauI/tWXo1Ll+gN5dHcxDPdm/Df1ufcDLCecn+pnCIVcdWE7CujXo8QaXOWRJyZyQWWbpB8eFwHzWXlv5mQ==",
+          "requires": {
+            "@babel/runtime": "^7.13.10",
+            "@radix-ui/react-compose-refs": "1.0.0"
+          }
+        },
+        "@radix-ui/react-use-layout-effect": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.0.tgz",
+          "integrity": "sha512-6Tpkq+R6LOlmQb1R5NNETLG0B4YP0wc+klfXafpUCj6JGyaUc8il7/kUZ7m59rGbXGczE9Bs+iz2qloqsZBduQ==",
+          "requires": {
+            "@babel/runtime": "^7.13.10"
+          }
+        }
       }
     },
     "@radix-ui/react-popper": {
@@ -28309,6 +28449,20 @@
         "@radix-ui/react-use-controllable-state": "0.1.0",
         "@radix-ui/react-use-previous": "0.1.1",
         "@radix-ui/react-use-size": "0.1.1"
+      },
+      "dependencies": {
+        "@radix-ui/react-label": {
+          "version": "0.1.5",
+          "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-0.1.5.tgz",
+          "integrity": "sha512-Au9+n4/DhvjR0IHhvZ1LPdx/OW+3CGDie30ZyCkbSHIuLp4/CV4oPPGBwJ1vY99Jog3zyQhsGww9MXj8O9Aj/A==",
+          "requires": {
+            "@babel/runtime": "^7.13.10",
+            "@radix-ui/react-compose-refs": "0.1.0",
+            "@radix-ui/react-context": "0.1.1",
+            "@radix-ui/react-id": "0.1.5",
+            "@radix-ui/react-primitive": "0.1.4"
+          }
+        }
       }
     },
     "@radix-ui/react-tabs": {
diff --git a/package.json b/package.json
index e346bd2..baff4d6 100644
--- a/package.json
+++ b/package.json
@@ -38,6 +38,7 @@
     "@radix-ui/react-accessible-icon": "^0.1.4",
     "@radix-ui/react-accordion": "^0.1.6",
     "@radix-ui/react-dialog": "^0.1.7",
+    "@radix-ui/react-label": "^1.0.0",
     "@radix-ui/react-switch": "^0.1.5",
     "@radix-ui/react-tabs": "^0.1.5",
     "@radix-ui/react-tooltip": "^0.1.7",
diff --git a/src/components/control-label/control-label.js b/src/components/control-label/control-label.js
deleted file mode 100644
index 4607773..0000000
--- a/src/components/control-label/control-label.js
+++ /dev/null
@@ -1,35 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-
-export default class ControlLabel extends React.PureComponent {
-  static propTypes = {
-    /** Label text */
-    text: PropTypes.string.isRequired,
-    /** Value should match the identifying id of the input element. */
-    id: PropTypes.string.isRequired,
-    /** Additional content to provide aligned to the right of the label. */
-    aside: PropTypes.node,
-    /** If true, label text adds (optional) alongside it. */
-    optional: PropTypes.bool,
-    /** A space separated list of Assembly class names to override the existing presentation. */
-    themeLabel: PropTypes.string
-  };
-
-  static defaultProps = {
-    themeLabel: 'txt-s txt-bold mb6'
-  };
-
-  render() {
-    const { text, id, aside, optional, themeLabel } = this.props;
-    const labelClasses = `inline-block ${themeLabel}`;
-
-    return (
-      <div>
-        <label htmlFor={id} className={labelClasses}>
-          {text} {optional && <span className="txt-normal">(optional)</span>}
-        </label>
-        {aside && <span className="inline-block ml12">{aside}</span>}
-      </div>
-    );
-  }
-}
diff --git a/src/components/control-label/control-label.tsx b/src/components/control-label/control-label.tsx
new file mode 100644
index 0000000..098c532
--- /dev/null
+++ b/src/components/control-label/control-label.tsx
@@ -0,0 +1,43 @@
+import React, { ReactNode, ReactElement } from 'react';
+import * as LabelPrimitive from '@radix-ui/react-label';
+import PropTypes from 'prop-types';
+
+interface Props {
+  id: string;
+  text: string;
+  aside?: ReactNode;
+  optional?: boolean;
+  themeLabel?: string;
+}
+
+export default function ControlLabel({
+  id,
+  text,
+  aside,
+  optional,
+  themeLabel = 'txt-s txt-bold mb6'
+}: Props): ReactElement {
+  return (
+    <div>
+      <LabelPrimitive.Root htmlFor={id} asChild>
+        <label className={`inline-block ${themeLabel}`}>
+          {text} {optional && <span className="txt-normal">(optional)</span>}
+        </label>
+      </LabelPrimitive.Root>
+      {aside && <span className="inline-block ml12">{aside}</span>}
+    </div>
+  );
+}
+
+ControlLabel.propTypes = {
+  /** Value should match the identifying id of the input element. */
+  id: PropTypes.string.isRequired,
+  /** Label text */
+  text: PropTypes.string.isRequired,
+  /** Additional content to provide aligned to the right of the label. */
+  aside: PropTypes.node,
+  /** If true, label text adds (optional) alongside it. */
+  optional: PropTypes.bool,
+  /** A space separated list of Assembly class names to override the existing presentation. */
+  themeLabel: PropTypes.string
+};
diff --git a/src/components/control-label/examples/control-label-example-basic.js b/src/components/control-label/examples/control-label-example-basic.js
deleted file mode 100644
index ed17a79..0000000
--- a/src/components/control-label/examples/control-label-example-basic.js
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
-Basic.
-*/
-import React from 'react';
-import ControlLabel from '../control-label';
-
-export default class Example extends React.Component {
-  render() {
-    return (
-      <div>
-        <ControlLabel id="name" text="Enter your name" />
-        <input id="name" type="text" placeholder="Enter name" />
-      </div>
-    );
-  }
-}
diff --git a/src/components/control-label/examples/control-label-example-basic.tsx b/src/components/control-label/examples/control-label-example-basic.tsx
new file mode 100644
index 0000000..cb06b56
--- /dev/null
+++ b/src/components/control-label/examples/control-label-example-basic.tsx
@@ -0,0 +1,14 @@
+/*
+Basic.
+*/
+import React from 'react';
+import ControlLabel from '../control-label';
+
+export default function Example() {
+  return (
+    <>
+      <ControlLabel id="name" text="Enter your name" />
+      <input id="name" type="text" placeholder="Enter name" />
+    </>
+  );
+}
diff --git a/src/components/icon-text/examples/icon-text-a.js b/src/components/icon-text/examples/icon-text-a.tsx
similarity index 100%
rename from src/components/icon-text/examples/icon-text-a.js
rename to src/components/icon-text/examples/icon-text-a.tsx
diff --git a/src/components/icon-text/examples/icon-text-b.js b/src/components/icon-text/examples/icon-text-b.tsx
similarity index 90%
rename from src/components/icon-text/examples/icon-text-b.js
rename to src/components/icon-text/examples/icon-text-b.tsx
index 3b36d80..a7c2f43 100644
--- a/src/components/icon-text/examples/icon-text-b.js
+++ b/src/components/icon-text/examples/icon-text-b.tsx
@@ -10,7 +10,7 @@ export default class Example extends React.Component {
       <button
         aria-label="Take me there"
         type="button"
-        className="link link-purple"
+        className="link link--purple"
       >
         <IconText iconAfter="chevron-right">Take me there</IconText>
       </button>
diff --git a/src/components/icon-text/examples/icon-text-c.tsx b/src/components/icon-text/examples/icon-text-c.tsx
new file mode 100644
index 0000000..ca69df4
--- /dev/null
+++ b/src/components/icon-text/examples/icon-text-c.tsx
@@ -0,0 +1,20 @@
+/*
+Inline, both icons and the child is JSX
+*/
+import React from 'react';
+import IconText from '../icon-text';
+import Icon from '../../icon';
+
+export default class Example extends React.Component {
+  render() {
+    return (
+      <IconText
+        inline={true}
+        iconBefore={<Icon name="github" />}
+        iconAfter="check"
+      >
+        <span className="txt-kbd">hi</span>
+      </IconText>
+    );
+  }
+}
diff --git a/src/components/icon-text/icon-text.js b/src/components/icon-text/icon-text.tsx
similarity index 58%
rename from src/components/icon-text/icon-text.js
rename to src/components/icon-text/icon-text.tsx
index 54e35e2..b68d682 100644
--- a/src/components/icon-text/icon-text.js
+++ b/src/components/icon-text/icon-text.tsx
@@ -1,40 +1,48 @@
-import React from 'react';
+import React, {ReactElement, ReactNode} from 'react';
 import PropTypes from 'prop-types';
 import Icon from '../icon';
 
+interface Props {
+  children: ReactNode;
+  iconBefore?: ReactNode;
+  iconAfter?: ReactNode;
+  inline?: boolean;
+}
+
 /**
  * Put an icon next to some text.
  *
  * The icon and text will be vertically centered, with standard spacing between.
  */
-class IconText extends React.Component {
-  renderIcon(icon) {
+export default function IconText({
+  children,
+  iconBefore,
+  iconAfter,
+  inline = false
+}: Props): ReactElement {
+
+  const renderIcon = (icon: ReactNode) => {
     if (typeof icon === 'string') {
       return <Icon name={icon} />;
     }
     return icon;
   }
 
-  render() {
-    const { props } = this;
-    const flexrule = props.inline ? 'inline-flex' : 'flex';
+  const before = !iconBefore ? null : (
+    <span className="mr6">{renderIcon(iconBefore)}</span>
+  );
 
-    const before = !props.iconBefore ? null : (
-      <span className="mr6">{this.renderIcon(props.iconBefore)}</span>
-    );
+  const after = !iconAfter ? null : (
+    <span className="ml6">{renderIcon(iconAfter)}</span>
+  );
 
-    const after = !props.iconAfter ? null : (
-      <span className="ml6">{this.renderIcon(props.iconAfter)}</span>
-    );
-
-    return (
-      <span className={`${flexrule} flex--center-cross`}>
-        {before}
-        <span>{props.children}</span>
-        {after}
-      </span>
-    );
-  }
+  return (
+    <span className={`${inline ? 'inline-flex' : 'flex'} flex--center-cross`}>
+      {before}
+      <span>{children}</span>
+      {after}
+    </span>
+  );
 }
 
 IconText.propTypes = {
@@ -44,10 +52,6 @@ IconText.propTypes = {
    * using `<span>`s instead of `<div>`s.
    */
   children: PropTypes.node.isRequired,
-  /**
-   * The size of the gap between the text and the icon: `"small"` or `"large"`.
-   */
-  gap: PropTypes.oneOf(['small', 'large']),
   /**
    * An icon to place before the text. If the value is a string, it should name an
    * Assembly icon. If you bring your own SVG or want finer-grained control over
@@ -64,10 +68,3 @@ IconText.propTypes = {
    */
   inline: PropTypes.bool
 };
-
-IconText.defaultProps = {
-  gap: 'small',
-  inline: false
-};
-
-export default IconText;
diff --git a/src/components/tabs/index.ts b/src/components/tabs/index.ts
deleted file mode 100644
index 3c0a201..0000000
--- a/src/components/tabs/index.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-import main from './tabs';
-
-export default main;


Test patch:
diff --git a/src/components/control-file/__snapshots__/control-file.test.js.snap b/src/components/control-file/__snapshots__/control-file.test.js.snap
index 026513d..4b70497 100644
--- a/src/components/control-file/__snapshots__/control-file.test.js.snap
+++ b/src/components/control-file/__snapshots__/control-file.test.js.snap
@@ -34,9 +34,7 @@ exports[`ControlFile all options renders 1`] = `
           className="txt-truncate"
         >
           <IconText
-            gap="small"
             iconBefore="harddrive"
-            inline={false}
           >
             Select an image
           </IconText>
@@ -77,7 +75,6 @@ exports[`ControlFile basic receives an array of one file as value, displaying it
     id="testinput-1"
     optional={false}
     text="Basic"
-    themeLabel="txt-s txt-bold mb6"
   />
   <div
     className="flex flex--center-cross overflow-hidden"
@@ -96,9 +93,7 @@ exports[`ControlFile basic receives an array of one file as value, displaying it
           className="txt-truncate"
         >
           <IconText
-            gap="small"
             iconBefore="harddrive"
-            inline={false}
           >
             bon jovi.mp3
           </IconText>
@@ -151,7 +146,6 @@ exports[`ControlFile basic renders 1`] = `
     id="testinput-1"
     optional={false}
     text="Basic"
-    themeLabel="txt-s txt-bold mb6"
   />
   <div
     className="flex flex--center-cross overflow-hidden"
@@ -170,9 +164,7 @@ exports[`ControlFile basic renders 1`] = `
           className="txt-truncate"
         >
           <IconText
-            gap="small"
             iconBefore="harddrive"
-            inline={false}
           >
             Select a file
           </IconText>
@@ -209,7 +201,6 @@ exports[`ControlFile disabled renders 1`] = `
     id="testinput-2"
     optional={false}
     text="Disabled"
-    themeLabel="txt-s txt-bold mb6"
   />
   <div
     className="flex flex--center-cross overflow-hidden"
@@ -228,9 +219,7 @@ exports[`ControlFile disabled renders 1`] = `
           className="txt-truncate"
         >
           <IconText
-            gap="small"
             iconBefore="harddrive"
-            inline={false}
           >
             Select a file
           </IconText>
@@ -267,7 +256,6 @@ exports[`ControlFile multiple receives an array of files as value, displaying th
     id="testinput-multiple"
     optional={false}
     text="Multiple"
-    themeLabel="txt-s txt-bold mb6"
   />
   <div
     className="flex flex--center-cross overflow-hidden"
@@ -286,9 +274,7 @@ exports[`ControlFile multiple receives an array of files as value, displaying th
           className="txt-truncate"
         >
           <IconText
-            gap="small"
             iconBefore="harddrive"
-            inline={false}
           >
             bon jovi.mp3, aerosmith.mp3
           </IconText>
diff --git a/src/components/control-label/__snapshots__/control-label.test.js.snap b/src/components/control-label/__snapshots__/control-label.test.js.snap
deleted file mode 100644
index d66efa4..0000000
--- a/src/components/control-label/__snapshots__/control-label.test.js.snap
+++ /dev/null
@@ -1,54 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`ControlLabel basic renders 1`] = `
-<div>
-  <label
-    className="inline-block txt-s txt-bold mb6"
-    htmlFor="label-id"
-  >
-    basic label
-     
-  </label>
-</div>
-`;
-
-exports[`ControlLabel basic with aside renders 1`] = `
-<div>
-  <label
-    className="inline-block txt-s txt-bold mb6"
-    htmlFor="label-id"
-  >
-    basic label
-     
-  </label>
-  <span
-    className="inline-block ml12"
-  >
-    <span>
-      Aside text
-    </span>
-  </span>
-</div>
-`;
-
-exports[`ControlLabel basic with optional renders 1`] = `
-<div>
-  <label
-    className="inline-block color-red"
-    htmlFor="label-id"
-  >
-    basic label
-     
-    <span
-      className="txt-normal"
-    >
-      (optional)
-    </span>
-  </label>
-  <span
-    className="inline-block ml12"
-  >
-    This is an aside
-  </span>
-</div>
-`;
diff --git a/src/components/control-label/__snapshots__/control-label.test.tsx.snap b/src/components/control-label/__snapshots__/control-label.test.tsx.snap
new file mode 100644
index 0000000..2613934
--- /dev/null
+++ b/src/components/control-label/__snapshots__/control-label.test.tsx.snap
@@ -0,0 +1,69 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`ControlLabel basic renders 1`] = `
+<body>
+  <div>
+    <div>
+      <label
+        class="inline-block txt-s txt-bold mb6"
+        id="radix-0"
+        role="label"
+      >
+        basic label
+         
+      </label>
+    </div>
+  </div>
+</body>
+`;
+
+exports[`ControlLabel basic with aside renders 1`] = `
+<body>
+  <div>
+    <div>
+      <label
+        class="inline-block txt-s txt-bold mb6"
+        id="radix-1"
+        role="label"
+      >
+        basic label
+         
+      </label>
+      <span
+        class="inline-block ml12"
+      >
+        <span>
+          Aside text
+        </span>
+      </span>
+    </div>
+  </div>
+</body>
+`;
+
+exports[`ControlLabel basic with optional renders 1`] = `
+<body>
+  <div>
+    <div>
+      <label
+        class="inline-block color-red"
+        id="radix-2"
+        role="label"
+      >
+        basic label
+         
+        <span
+          class="txt-normal"
+        >
+          (optional)
+        </span>
+      </label>
+      <span
+        class="inline-block ml12"
+      >
+        This is an aside
+      </span>
+    </div>
+  </div>
+</body>
+`;
diff --git a/src/components/control-label/control-label-test-cases.js b/src/components/control-label/control-label-test-cases.js
deleted file mode 100644
index a7aa9c6..0000000
--- a/src/components/control-label/control-label-test-cases.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import React from 'react';
-import ControlLabel from './control-label';
-
-const testCases = {};
-
-testCases.basic = {
-  description: 'basic',
-  component: ControlLabel,
-  props: {
-    text: 'basic label',
-    id: 'label-id'
-  }
-};
-
-testCases.basicWithAside = {
-  description: 'basic with aside',
-  component: ControlLabel,
-  props: {
-    text: 'basic label',
-    id: 'label-id',
-    aside: <span>Aside text</span>
-  }
-};
-
-testCases.basicWithOptional = {
-  description: 'basic with optional',
-  component: ControlLabel,
-  props: {
-    text: 'basic label',
-    id: 'label-id',
-    aside: 'This is an aside',
-    optional: true,
-    themeLabel: 'color-red'
-  }
-};
-
-export { testCases };
diff --git a/src/components/control-label/control-label.test.js b/src/components/control-label/control-label.test.js
deleted file mode 100644
index 6b8e9d8..0000000
--- a/src/components/control-label/control-label.test.js
+++ /dev/null
@@ -1,47 +0,0 @@
-import React from 'react';
-import { shallow } from 'enzyme';
-import { testCases } from './control-label-test-cases';
-
-describe('ControlLabel', () => {
-  let testCase;
-  let wrapper;
-
-  describe(testCases.basic.description, () => {
-    beforeEach(() => {
-      testCase = testCases.basic;
-      wrapper = shallow(
-        React.createElement(testCase.component, testCase.props)
-      );
-    });
-
-    test('renders', () => {
-      expect(wrapper).toMatchSnapshot();
-    });
-  });
-
-  describe(testCases.basicWithAside.description, () => {
-    beforeEach(() => {
-      testCase = testCases.basicWithAside;
-      wrapper = shallow(
-        React.createElement(testCase.component, testCase.props)
-      );
-    });
-
-    test('renders', () => {
-      expect(wrapper).toMatchSnapshot();
-    });
-  });
-
-  describe(testCases.basicWithOptional.description, () => {
-    beforeEach(() => {
-      testCase = testCases.basicWithOptional;
-      wrapper = shallow(
-        React.createElement(testCase.component, testCase.props)
-      );
-    });
-
-    test('renders', () => {
-      expect(wrapper).toMatchSnapshot();
-    });
-  });
-});
diff --git a/src/components/control-label/control-label.test.tsx b/src/components/control-label/control-label.test.tsx
new file mode 100644
index 0000000..e464092
--- /dev/null
+++ b/src/components/control-label/control-label.test.tsx
@@ -0,0 +1,46 @@
+import React from 'react';
+import { render } from '@testing-library/react';
+import ControlLabel from './control-label';
+
+describe('ControlLabel', () => {
+
+  describe('basic', () => {
+    const props = {
+      text: 'basic label',
+      id: 'label-id'
+    };
+
+    test('renders', () => {
+      const { baseElement } = render(<ControlLabel {...props} />)
+      expect(baseElement).toMatchSnapshot();
+    });
+  });
+
+  describe('basic with aside', () => {
+    const props = {
+      text: 'basic label',
+      id: 'label-id',
+      aside: <span>Aside text</span>
+    };
+
+    test('renders', () => {
+      const { baseElement } = render(<ControlLabel {...props} />)
+      expect(baseElement).toMatchSnapshot();
+    });
+  });
+
+  describe('basic with optional', () => {
+    const props = {
+      text: 'basic label',
+      id: 'label-id',
+      aside: 'This is an aside',
+      optional: true,
+      themeLabel: 'color-red'
+    };
+
+    test('renders', () => {
+      const { baseElement } = render(<ControlLabel {...props} />)
+      expect(baseElement).toMatchSnapshot();
+    });
+  });
+});
diff --git a/src/components/control-range/__snapshots__/control-range.test.js.snap b/src/components/control-range/__snapshots__/control-range.test.js.snap
index fd08f8a..4601925 100644
--- a/src/components/control-range/__snapshots__/control-range.test.js.snap
+++ b/src/components/control-range/__snapshots__/control-range.test.js.snap
@@ -46,7 +46,6 @@ exports[`ControlRange basic onChange gets called with input id and value 1`] = `
     id="testinput"
     optional={false}
     text="Basic"
-    themeLabel="txt-s txt-bold mb6"
   />
   <div
     className="range "
@@ -72,7 +71,6 @@ exports[`ControlRange basic renders 1`] = `
     id="testinput"
     optional={false}
     text="Basic"
-    themeLabel="txt-s txt-bold mb6"
   />
   <div
     className="range "
@@ -98,7 +96,6 @@ exports[`ControlRange disabled renders 1`] = `
     id="testinput"
     optional={false}
     text="Disabled"
-    themeLabel="txt-s txt-bold mb6"
   />
   <div
     className="range "
diff --git a/src/components/control-select/__snapshots__/control-select.test.js.snap b/src/components/control-select/__snapshots__/control-select.test.js.snap
index 586a99e..0b98787 100644
--- a/src/components/control-select/__snapshots__/control-select.test.js.snap
+++ b/src/components/control-select/__snapshots__/control-select.test.js.snap
@@ -8,7 +8,6 @@ exports[`ControlSelect Supported values renders 1`] = `
     id="value"
     optional={false}
     text="Basic"
-    themeLabel="txt-s txt-bold mb6"
   />
   <div
     className="select-container "
@@ -114,7 +113,6 @@ exports[`ControlSelect basic onChange gets called with input id and value 1`] =
     id="testinput"
     optional={false}
     text="Basic"
-    themeLabel="txt-s txt-bold mb6"
   />
   <div
     className="select-container "
@@ -156,7 +154,6 @@ exports[`ControlSelect basic renders 1`] = `
     id="testinput"
     optional={false}
     text="Basic"
-    themeLabel="txt-s txt-bold mb6"
   />
   <div
     className="select-container "
@@ -198,7 +195,6 @@ exports[`ControlSelect disabled renders 1`] = `
     id="disabled"
     optional={false}
     text="Disabled"
-    themeLabel="txt-s txt-bold mb6"
   />
   <div
     className="select-container "
@@ -240,7 +236,6 @@ exports[`ControlSelect grouped dropdown options renders 1`] = `
     id="grouped"
     optional={false}
     text="Grouped dropdown options"
-    themeLabel="txt-s txt-bold mb6"
   />
   <div
     className="select-container "
diff --git a/src/components/control-text/__snapshots__/control-text.test.js.snap b/src/components/control-text/__snapshots__/control-text.test.js.snap
index 781b42f..fd96f6f 100644
--- a/src/components/control-text/__snapshots__/control-text.test.js.snap
+++ b/src/components/control-text/__snapshots__/control-text.test.js.snap
@@ -81,7 +81,6 @@ exports[`ControlText basic onChange gets called with input id and value 1`] = `
     id="testinput"
     optional={false}
     text="Basic"
-    themeLabel="txt-s txt-bold mb6"
   />
   <input
     aria-required={true}
@@ -104,7 +103,6 @@ exports[`ControlText basic renders 1`] = `
     id="testinput"
     optional={false}
     text="Basic"
-    themeLabel="txt-s txt-bold mb6"
   />
   <input
     aria-required={true}
@@ -128,7 +126,6 @@ exports[`ControlText default validation error renders 1`] = `
     id="testinput"
     optional={false}
     text="Validation error"
-    themeLabel="txt-s txt-bold mb6"
   />
   <input
     aria-invalid={true}
@@ -152,7 +149,6 @@ exports[`ControlText disabled renders 1`] = `
     id="testinput"
     optional={false}
     text="Disabled"
-    themeLabel="txt-s txt-bold mb6"
   />
   <input
     aria-required={true}
@@ -176,7 +172,6 @@ exports[`ControlText error inline option renders 1`] = `
     id="testinput"
     optional={false}
     text="Error inline"
-    themeLabel="txt-s txt-bold mb6"
   />
   <div
     className="flex"
diff --git a/src/components/control-textarea/__snapshots__/control-textarea.test.js.snap b/src/components/control-textarea/__snapshots__/control-textarea.test.js.snap
index d54dce9..7e66689 100644
--- a/src/components/control-textarea/__snapshots__/control-textarea.test.js.snap
+++ b/src/components/control-textarea/__snapshots__/control-textarea.test.js.snap
@@ -43,7 +43,6 @@ exports[`ControlToggleSet basic onChange gets called with input id and value 1`]
     id="testinput"
     optional={false}
     text="Basic"
-    themeLabel="txt-s txt-bold mb6"
   />
   <textarea
     aria-required={true}
@@ -65,7 +64,6 @@ exports[`ControlToggleSet basic renders 1`] = `
     id="testinput"
     optional={false}
     text="Basic"
-    themeLabel="txt-s txt-bold mb6"
   />
   <textarea
     aria-required={true}
@@ -87,7 +85,6 @@ exports[`ControlToggleSet disabled renders 1`] = `
     id="testinput"
     optional={false}
     text="Disabled"
-    themeLabel="txt-s txt-bold mb6"
   />
   <textarea
     aria-required={true}
diff --git a/src/components/icon-text/__snapshots__/icon-text.test.js.snap b/src/components/icon-text/__snapshots__/icon-text.test.js.snap
deleted file mode 100644
index 68fb052..0000000
--- a/src/components/icon-text/__snapshots__/icon-text.test.js.snap
+++ /dev/null
@@ -1,93 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`icon after renders as expected 1`] = `
-<span
-  className="flex flex--center-cross"
->
-  <span>
-    Next
-  </span>
-  <span
-    className="ml6"
-  >
-    <Icon
-      name="chevron-right"
-    />
-  </span>
-</span>
-`;
-
-exports[`icon before renders as expected 1`] = `
-<span
-  className="flex flex--center-cross"
->
-  <span
-    className="mr6"
-  >
-    <Icon
-      name="clipboard"
-    />
-  </span>
-  <span>
-    Copy
-  </span>
-</span>
-`;
-
-exports[`icons on both sides, including a non-string one renders as expected 1`] = `
-<span
-  className="flex flex--center-cross"
->
-  <span
-    className="mr6"
-  >
-    <Icon
-      name="check"
-    />
-  </span>
-  <span>
-    What
-  </span>
-  <span
-    className="ml6"
-  >
-    <Icon
-      name="github"
-    />
-  </span>
-</span>
-`;
-
-exports[`inline flex parent renders as expected 1`] = `
-<span
-  className="inline-flex flex--center-cross"
->
-  <span
-    className="mr6"
-  >
-    <Icon
-      name="polyline"
-    />
-  </span>
-  <span>
-    Inline!
-  </span>
-</span>
-`;
-
-exports[`large gap renders as expected 1`] = `
-<span
-  className="flex flex--center-cross"
->
-  <span
-    className="mr6"
-  >
-    <Icon
-      name="check"
-    />
-  </span>
-  <span>
-    Done
-  </span>
-</span>
-`;
diff --git a/src/components/icon-text/__snapshots__/icon-text.test.tsx.snap b/src/components/icon-text/__snapshots__/icon-text.test.tsx.snap
new file mode 100644
index 0000000..417fb50
--- /dev/null
+++ b/src/components/icon-text/__snapshots__/icon-text.test.tsx.snap
@@ -0,0 +1,164 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`IconText both icons renders 1`] = `
+<body>
+  <div>
+    <span
+      class="flex flex--center-cross"
+    >
+      <span
+        class="mr6"
+      >
+        <svg
+          aria-hidden="true"
+          class="events-none icon"
+          data-testid="icon-check"
+          focusable="false"
+          style="width: 18px; height: 18px;"
+        >
+          <use
+            xlink:href="#icon-check"
+            xmlns:xlink="http://www.w3.org/1999/xlink"
+          />
+        </svg>
+        <span
+          style="position: absolute; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0px, 0px, 0px, 0px); white-space: nowrap; word-wrap: normal;"
+        >
+          check
+        </span>
+      </span>
+      <span>
+        What
+      </span>
+      <span
+        class="ml6"
+      >
+        <svg
+          aria-hidden="true"
+          class="events-none icon"
+          data-testid="icon-github"
+          focusable="false"
+          style="width: 18px; height: 18px;"
+        >
+          <use
+            xlink:href="#icon-github"
+            xmlns:xlink="http://www.w3.org/1999/xlink"
+          />
+        </svg>
+        <span
+          style="position: absolute; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0px, 0px, 0px, 0px); white-space: nowrap; word-wrap: normal;"
+        >
+          github
+        </span>
+      </span>
+    </span>
+  </div>
+</body>
+`;
+
+exports[`IconText icon after renders 1`] = `
+<body>
+  <div>
+    <span
+      class="flex flex--center-cross"
+    >
+      <span>
+        Next
+      </span>
+      <span
+        class="ml6"
+      >
+        <svg
+          aria-hidden="true"
+          class="events-none icon"
+          data-testid="icon-chevron-right"
+          focusable="false"
+          style="width: 18px; height: 18px;"
+        >
+          <use
+            xlink:href="#icon-chevron-right"
+            xmlns:xlink="http://www.w3.org/1999/xlink"
+          />
+        </svg>
+        <span
+          style="position: absolute; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0px, 0px, 0px, 0px); white-space: nowrap; word-wrap: normal;"
+        >
+          chevron-right
+        </span>
+      </span>
+    </span>
+  </div>
+</body>
+`;
+
+exports[`IconText icon before renders 1`] = `
+<body>
+  <div>
+    <span
+      class="flex flex--center-cross"
+    >
+      <span
+        class="mr6"
+      >
+        <svg
+          aria-hidden="true"
+          class="events-none icon"
+          data-testid="icon-clipboard"
+          focusable="false"
+          style="width: 18px; height: 18px;"
+        >
+          <use
+            xlink:href="#icon-clipboard"
+            xmlns:xlink="http://www.w3.org/1999/xlink"
+          />
+        </svg>
+        <span
+          style="position: absolute; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0px, 0px, 0px, 0px); white-space: nowrap; word-wrap: normal;"
+        >
+          clipboard
+        </span>
+      </span>
+      <span>
+        Copy
+      </span>
+    </span>
+  </div>
+</body>
+`;
+
+exports[`IconText inline flex parent renders 1`] = `
+<body>
+  <div>
+    <span
+      class="inline-flex flex--center-cross"
+    >
+      <span
+        class="mr6"
+      >
+        <svg
+          aria-hidden="true"
+          class="events-none icon"
+          data-testid="icon-polyline"
+          focusable="false"
+          style="width: 18px; height: 18px;"
+        >
+          <use
+            xlink:href="#icon-polyline"
+            xmlns:xlink="http://www.w3.org/1999/xlink"
+          />
+        </svg>
+        <span
+          style="position: absolute; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0px, 0px, 0px, 0px); white-space: nowrap; word-wrap: normal;"
+        >
+          polyline
+        </span>
+      </span>
+      <span>
+        <span>
+          Inline
+        </span>
+      </span>
+    </span>
+  </div>
+</body>
+`;
diff --git a/src/components/icon-text/icon-text-test-cases.js b/src/components/icon-text/icon-text-test-cases.js
deleted file mode 100644
index 11192db..0000000
--- a/src/components/icon-text/icon-text-test-cases.js
+++ /dev/null
@@ -1,68 +0,0 @@
-import React from 'react';
-import IconText from './icon-text';
-import Icon from '../icon';
-
-const testCases = {};
-
-testCases.iconBefore = {
-  description: 'icon before',
-  component: IconText,
-  props: {
-    children: 'Copy',
-    iconBefore: 'clipboard'
-  }
-};
-
-testCases.iconAfter = {
-  description: 'icon after',
-  component: IconText,
-  props: {
-    children: 'Next',
-    iconAfter: 'chevron-right'
-  }
-};
-
-testCases.largeSpacing = {
-  description: 'large gap',
-  component: IconText,
-  props: {
-    children: 'Done',
-    iconBefore: 'check',
-    gap: 'large'
-  }
-};
-
-testCases.bothIcons = {
-  description: 'icons on both sides, including a non-string one',
-  component: IconText,
-  props: {
-    children: 'What',
-    iconBefore: 'check',
-    iconAfter: <Icon name="github" />
-  }
-};
-
-testCases.buttonyDisplay = {
-  description: 'a buttony look',
-  element: (
-    <button
-      aria-label="Duplicate"
-      type="button"
-      className="link txt-bold txt-s block"
-    >
-      <IconText iconBefore="duplicate">Duplicate</IconText>
-    </button>
-  )
-};
-
-testCases.flexParentInline = {
-  description: 'inline flex parent',
-  component: IconText,
-  props: {
-    children: 'Inline!',
-    iconBefore: 'polyline',
-    inline: true
-  }
-};
-
-export { testCases };
diff --git a/src/components/icon-text/icon-text.test.js b/src/components/icon-text/icon-text.test.js
deleted file mode 100644
index 1a31d0e..0000000
--- a/src/components/icon-text/icon-text.test.js
+++ /dev/null
@@ -1,61 +0,0 @@
-import React from 'react';
-import { shallow } from 'enzyme';
-import { testCases } from './icon-text-test-cases';
-
-let testCase;
-let wrapper;
-
-describe(testCases.iconBefore.description, () => {
-  beforeEach(() => {
-    testCase = testCases.iconBefore;
-    wrapper = shallow(React.createElement(testCase.component, testCase.props));
-  });
-
-  test('renders as expected', () => {
-    expect(wrapper).toMatchSnapshot();
-  });
-});
-
-describe(testCases.iconAfter.description, () => {
-  beforeEach(() => {
-    testCase = testCases.iconAfter;
-    wrapper = shallow(React.createElement(testCase.component, testCase.props));
-  });
-
-  test('renders as expected', () => {
-    expect(wrapper).toMatchSnapshot();
-  });
-});
-
-describe(testCases.largeSpacing.description, () => {
-  beforeEach(() => {
-    testCase = testCases.largeSpacing;
-    wrapper = shallow(React.createElement(testCase.component, testCase.props));
-  });
-
-  test('renders as expected', () => {
-    expect(wrapper).toMatchSnapshot();
-  });
-});
-
-describe(testCases.bothIcons.description, () => {
-  beforeEach(() => {
-    testCase = testCases.bothIcons;
-    wrapper = shallow(React.createElement(testCase.component, testCase.props));
-  });
-
-  test('renders as expected', () => {
-    expect(wrapper).toMatchSnapshot();
-  });
-});
-
-describe(testCases.flexParentInline.description, () => {
-  beforeEach(() => {
-    testCase = testCases.flexParentInline;
-    wrapper = shallow(React.createElement(testCase.component, testCase.props));
-  });
-
-  test('renders as expected', () => {
-    expect(wrapper).toMatchSnapshot();
-  });
-});
diff --git a/src/components/icon-text/icon-text.test.tsx b/src/components/icon-text/icon-text.test.tsx
new file mode 100644
index 0000000..d3b37b6
--- /dev/null
+++ b/src/components/icon-text/icon-text.test.tsx
@@ -0,0 +1,57 @@
+import React from 'react';
+import { render } from '@testing-library/react';
+import IconText from './icon-text';
+import Icon from '../icon';
+
+describe('IconText', () => {
+  describe('icon before', () => {
+    const props = {
+      children: 'Copy',
+      iconBefore: 'clipboard'
+    };
+
+    test('renders', () => {
+      const { baseElement } = render(<IconText {...props} />)
+      expect(baseElement).toMatchSnapshot();
+    });
+  });
+
+  describe('icon after', () => {
+    const props = {
+      children: 'Next',
+      iconAfter: 'chevron-right'
+    };
+
+    test('renders', () => {
+      const { baseElement } = render(<IconText {...props} />)
+      expect(baseElement).toMatchSnapshot();
+    });
+  });
+
+  describe('both icons', () => {
+    const props = {
+      children: 'What',
+      iconBefore: 'check',
+      iconAfter: <Icon name="github" />
+    };
+
+    test('renders', () => {
+      const { baseElement } = render(<IconText {...props} />)
+      expect(baseElement).toMatchSnapshot();
+    });
+  });
+
+  describe('inline flex parent', () => {
+    const props = {
+      children: <span>Inline</span>,
+      iconBefore: 'polyline',
+      inline: true
+    };
+
+    test('renders', () => {
+      const { baseElement } = render(<IconText {...props} />)
+      expect(baseElement).toMatchSnapshot();
+    });
+  });
+
+});
diff --git a/src/components/icon/__snapshots__/icon.test.tsx.snap b/src/components/icon/__snapshots__/icon.test.tsx.snap
index 9b593d3..7ca007e 100644
--- a/src/components/icon/__snapshots__/icon.test.tsx.snap
+++ b/src/components/icon/__snapshots__/icon.test.tsx.snap
@@ -1,30 +1,31 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`inline renders 1`] = `
+exports[`basic passthrough prop 1`] = `
 <body>
   <div>
     <svg
       aria-hidden="true"
-      class="events-none icon inline-block align-t"
-      data-testid="icon-check"
+      class="events-none icon"
+      data-test="alert-icon"
+      data-testid="icon-alert"
       focusable="false"
-      style="width: 18px; height: 14px;"
+      style="width: 18px; height: 18px;"
     >
       <use
-        xlink:href="#icon-check"
+        xlink:href="#icon-alert"
         xmlns:xlink="http://www.w3.org/1999/xlink"
       />
     </svg>
     <span
       style="position: absolute; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0px, 0px, 0px, 0px); white-space: nowrap; word-wrap: normal;"
     >
-      check
+      alert
     </span>
   </div>
 </body>
 `;
 
-exports[`renders basic 1`] = `
+exports[`basic renders 1`] = `
 <body>
   <div>
     <svg
@@ -48,16 +49,15 @@ exports[`renders basic 1`] = `
 </body>
 `;
 
-exports[`renders passthrough prop 1`] = `
+exports[`basic special size 1`] = `
 <body>
   <div>
     <svg
       aria-hidden="true"
       class="events-none icon"
-      data-test="alert-icon"
       data-testid="icon-alert"
       focusable="false"
-      style="width: 18px; height: 18px;"
+      style="width: 36px; height: 36px;"
     >
       <use
         xlink:href="#icon-alert"
@@ -73,15 +73,16 @@ exports[`renders passthrough prop 1`] = `
 </body>
 `;
 
-exports[`renders special size 1`] = `
+exports[`basic special size via style 1`] = `
 <body>
   <div>
     <svg
       aria-hidden="true"
       class="events-none icon"
+      data-test="alert-icon"
       data-testid="icon-alert"
       focusable="false"
-      style="width: 36px; height: 36px;"
+      style="height: 36px; width: 36px;"
     >
       <use
         xlink:href="#icon-alert"
@@ -97,26 +98,25 @@ exports[`renders special size 1`] = `
 </body>
 `;
 
-exports[`renders special size via style 1`] = `
+exports[`inline renders 1`] = `
 <body>
   <div>
     <svg
       aria-hidden="true"
-      class="events-none icon"
-      data-test="alert-icon"
-      data-testid="icon-alert"
+      class="events-none icon inline-block align-t"
+      data-testid="icon-check"
       focusable="false"
-      style="height: 36px; width: 36px;"
+      style="width: 18px; height: 14px;"
     >
       <use
-        xlink:href="#icon-alert"
+        xlink:href="#icon-check"
         xmlns:xlink="http://www.w3.org/1999/xlink"
       />
     </svg>
     <span
       style="position: absolute; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0px, 0px, 0px, 0px); white-space: nowrap; word-wrap: normal;"
     >
-      alert
+      check
     </span>
   </div>
 </body>
diff --git a/src/components/icon/icon.test.tsx b/src/components/icon/icon.test.tsx
index 77fc0f9..1a00827 100644
--- a/src/components/icon/icon.test.tsx
+++ b/src/components/icon/icon.test.tsx
@@ -8,8 +8,8 @@ jest.mock('../utils/get-window');
 // eslint-disable-next-line @typescript-eslint/no-explicit-any
 const getWindowMock = getWindow as any;
 
-describe('renders', () => {
-  test('basic', () => {
+describe('basic', () => {
+  test('renders', () => {
     const { baseElement } = render(<Icon name='bike' />)
     expect(baseElement).toMatchSnapshot();
   });