Repository: mapbox/mr-ui (ts)

Issue:
Rewrite control-label component
### Criteria:

- TypeScript
- Functional component
- Radix inner workings. Here's the API Reference for label: https://www.radix-ui.com/docs/primitives/components/label#api-reference

Pull request:
Rewrite control-label
Simple changes to the control-label component to use TypeScript, React testing library, and accessibility enhancements provided by [`@radix-ui/react-label`](https://www.radix-ui.com/docs/primitives/components/label#api-reference).

---

Closes #189 



Patch:
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/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..bc736cf 100644
--- a/src/components/control-file/__snapshots__/control-file.test.js.snap
+++ b/src/components/control-file/__snapshots__/control-file.test.js.snap
@@ -77,7 +77,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"
@@ -151,7 +150,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"
@@ -209,7 +207,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"
@@ -267,7 +264,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"
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/__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();
   });