diff --git a/ui/components/component-library/component-library-components.scss b/ui/components/component-library/component-library-components.scss
index af5003d1e..e360bf5f9 100644
--- a/ui/components/component-library/component-library-components.scss
+++ b/ui/components/component-library/component-library-components.scss
@@ -10,6 +10,7 @@
@import 'button-primary/button-primary';
@import 'button-secondary/button-secondary';
@import 'icon/icon';
+@import 'label/label';
@import 'tag/tag';
@import 'text/text';
@import 'text-field/text-field';
diff --git a/ui/components/component-library/label/README.mdx b/ui/components/component-library/label/README.mdx
new file mode 100644
index 000000000..66868610f
--- /dev/null
+++ b/ui/components/component-library/label/README.mdx
@@ -0,0 +1,95 @@
+import { Story, Canvas, ArgsTable } from '@storybook/addon-docs';
+
+import { Label } from './label';
+
+# Label
+
+The `Label` is a component used to label form inputs.
+
+
+
+## Props
+
+The `Label` accepts all props below as well as all [Text](/docs/ui-components-component-library-text-text-stories-js--default-story#props) and [Box](/docs/ui-components-ui-box-box-stories-js--default-story#props) component props.
+
+
+
+### Children
+
+The `children` of the label can be text or a react node.
+
+
+
+```jsx
+import { DISPLAY, ALIGN_ITEMS, FLEX_DIRECTION, SIZES, COLORS } from '../../../helpers/constants/design-system';
+import { Icon, ICON_NAMES } from '../../ui/component-library/icon';
+import { Label } from '../../ui/component-library/label';
+import { TextFieldBase } from '../../ui/component-library/text-field-base'
+
+
+
+
+```
+
+### Html For
+
+Use the `htmlFor` prop to allow the `Label` to focus on an input with the same id when clicked. The cursor will also change to a `pointer` when the `htmlFor` has a value
+
+
+
+```jsx
+import { TextFieldBase } from '../../ui/component-library/text-field-base';
+import { Label } from '../../ui/component-library/label';
+
+
+
+```
+
+### Required
+
+Use the `required` prop to add a required red asterisk next to the `children` of the `Label`. Note the required asterisk will always render after the `children`.
+
+
+
+```jsx
+import { Label } from '../../ui/component-library/label';
+
+;
+```
+
+### Disabled
+
+Use the `disabled` prop to set the `Label` in disabled state
+
+
+
+```jsx
+import { Label } from '../../ui/component-library/label';
+
+;
+```
diff --git a/ui/components/component-library/label/index.js b/ui/components/component-library/label/index.js
new file mode 100644
index 000000000..f28365d90
--- /dev/null
+++ b/ui/components/component-library/label/index.js
@@ -0,0 +1 @@
+export { Label } from './label';
diff --git a/ui/components/component-library/label/label.js b/ui/components/component-library/label/label.js
new file mode 100644
index 000000000..aece4d958
--- /dev/null
+++ b/ui/components/component-library/label/label.js
@@ -0,0 +1,73 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import classnames from 'classnames';
+
+import {
+ COLORS,
+ FONT_WEIGHT,
+ TEXT,
+ DISPLAY,
+ ALIGN_ITEMS,
+} from '../../../helpers/constants/design-system';
+import { Text } from '../text';
+
+export const Label = ({
+ htmlFor,
+ required,
+ disabled,
+ className,
+ children,
+ ...props
+}) => (
+
+ {children}
+ {required && (
+
+ *
+
+ )}
+
+);
+
+Label.propTypes = {
+ /**
+ * The content of the label
+ */
+ children: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
+ /**
+ * The id of the input associated with the label
+ */
+ htmlFor: PropTypes.string,
+ /**
+ * If true the label will display as required
+ */
+ required: PropTypes.bool,
+ /**
+ * Whether the label is disabled or not
+ */
+ disabled: PropTypes.bool,
+ /**
+ * Additional classNames to be added to the label component
+ */
+ className: PropTypes.string,
+};
diff --git a/ui/components/component-library/label/label.scss b/ui/components/component-library/label/label.scss
new file mode 100644
index 000000000..425048540
--- /dev/null
+++ b/ui/components/component-library/label/label.scss
@@ -0,0 +1,11 @@
+.mm-label {
+ --label-opacity-disabled: 0.5; // TODO: replace with design token
+
+ &--html-for {
+ cursor: pointer;
+ }
+
+ &--disabled {
+ opacity: var(--label-opacity-disabled);
+ }
+}
diff --git a/ui/components/component-library/label/label.stories.js b/ui/components/component-library/label/label.stories.js
new file mode 100644
index 000000000..0d3048bbc
--- /dev/null
+++ b/ui/components/component-library/label/label.stories.js
@@ -0,0 +1,112 @@
+import React, { useState } from 'react';
+import {
+ DISPLAY,
+ FLEX_DIRECTION,
+ COLORS,
+ SIZES,
+ ALIGN_ITEMS,
+} from '../../../helpers/constants/design-system';
+
+import Box from '../../ui/box';
+import { Icon, ICON_NAMES } from '../icon';
+import { TextFieldBase } from '../text-field-base';
+
+import { Label } from './label';
+
+import README from './README.mdx';
+
+export default {
+ title: 'Components/ComponentLibrary/Label',
+ id: __filename,
+ component: Label,
+ parameters: {
+ docs: {
+ page: README,
+ },
+ },
+ argTypes: {
+ htmlFor: {
+ control: 'text',
+ },
+ required: {
+ control: 'boolean',
+ },
+ disabled: {
+ control: 'boolean',
+ },
+ children: {
+ control: 'text',
+ },
+ className: {
+ control: 'text',
+ },
+ },
+ args: {
+ children: 'Label',
+ },
+};
+
+const Template = (args) => ;
+
+export const DefaultStory = Template.bind({});
+DefaultStory.storyName = 'Default';
+
+export const Children = (args) => (
+
+
+
+
+
+);
+
+export const HtmlFor = (args) => {
+ const [value, setValue] = useState('');
+ const handleOnChange = (e) => {
+ setValue(e.target.value);
+ };
+ return (
+
+
+
+
+ );
+};
+HtmlFor.args = {
+ children: 'Network name',
+ htmlFor: 'add-network',
+};
+
+export const Required = Template.bind({});
+Required.args = {
+ required: true,
+};
+
+export const Disabled = Template.bind({});
+Disabled.args = {
+ disabled: true,
+};
diff --git a/ui/components/component-library/label/label.test.js b/ui/components/component-library/label/label.test.js
new file mode 100644
index 000000000..44c703912
--- /dev/null
+++ b/ui/components/component-library/label/label.test.js
@@ -0,0 +1,67 @@
+/* eslint-disable jest/require-top-level-describe */
+import { fireEvent, render } from '@testing-library/react';
+import React from 'react';
+import { Icon, ICON_NAMES } from '../icon';
+import { TextFieldBase } from '../text-field-base';
+
+import { Label } from './label';
+
+describe('label', () => {
+ it('should render text inside the label', () => {
+ const { getByText } = render();
+ expect(getByText('label')).toBeDefined();
+ });
+ it('should render text and react nodes as children', () => {
+ const { getByText, getByTestId } = render(
+ ,
+ );
+ expect(getByText('label')).toBeDefined();
+ expect(getByTestId('icon')).toBeDefined();
+ });
+ it('should be able to accept an htmlFor prop and focus an input of a given id', () => {
+ const { getByText, getByRole } = render(
+ <>
+
+
+ >,
+ );
+ const input = getByRole('textbox');
+ const label = getByText('label');
+ expect(label).toBeDefined();
+ expect(input).not.toHaveFocus();
+ fireEvent.click(label);
+ expect(input).toHaveFocus();
+ });
+ it('should render when wrapping an input and focus input when clicked without htmlFor', () => {
+ const { getByText, getByRole } = render(
+ <>
+
+ >,
+ );
+ const input = getByRole('textbox');
+ const label = getByText('Label text');
+ expect(label).toBeDefined();
+ expect(input).not.toHaveFocus();
+ fireEvent.click(label);
+ expect(input).toHaveFocus();
+ });
+ it('should render with required asterisk', () => {
+ const { getByText } = render();
+ expect(getByText('label')).toBeDefined();
+ expect(getByText('*')).toBeDefined();
+ });
+ it('should render with disabled state and have disabled class', () => {
+ const { getByText } = render();
+ expect(getByText('label')).toHaveClass('mm-label--disabled');
+ });
+ it('should render with additional className', () => {
+ const { getByText } = render();
+ expect(getByText('label')).toHaveClass('test-class');
+ });
+});