diff --git a/package.json b/package.json
index 47ed5e110b000..4c2ba4e3d0bb6 100644
--- a/package.json
+++ b/package.json
@@ -136,6 +136,7 @@
     "@kbn/logging": "link:bazel-bin/packages/kbn-logging",
     "@kbn/mapbox-gl": "link:bazel-bin/packages/kbn-mapbox-gl",
     "@kbn/monaco": "link:bazel-bin/packages/kbn-monaco",
+    "@kbn/react-field": "link:bazel-bin/packages/kbn-react-field",
     "@kbn/rule-data-utils": "link:bazel-bin/packages/kbn-rule-data-utils",
     "@kbn/securitysolution-autocomplete": "link:bazel-bin/packages/kbn-securitysolution-autocomplete",
     "@kbn/securitysolution-es-utils": "link:bazel-bin/packages/kbn-securitysolution-es-utils",
diff --git a/packages/BUILD.bazel b/packages/BUILD.bazel
index ace4f982b8515..b52fb056380ee 100644
--- a/packages/BUILD.bazel
+++ b/packages/BUILD.bazel
@@ -36,6 +36,7 @@ filegroup(
       "//packages/kbn-optimizer:build",
       "//packages/kbn-plugin-generator:build",
       "//packages/kbn-plugin-helpers:build",
+      "//packages/kbn-react-field:build",
       "//packages/kbn-rule-data-utils:build",
       "//packages/kbn-securitysolution-autocomplete:build",
       "//packages/kbn-securitysolution-list-constants:build",
diff --git a/packages/kbn-optimizer/src/worker/webpack.config.ts b/packages/kbn-optimizer/src/worker/webpack.config.ts
index 9a0863237fab1..6a76e23b7b3e9 100644
--- a/packages/kbn-optimizer/src/worker/webpack.config.ts
+++ b/packages/kbn-optimizer/src/worker/webpack.config.ts
@@ -28,6 +28,14 @@ const IS_CODE_COVERAGE = !!process.env.CODE_COVERAGE;
 const ISTANBUL_PRESET_PATH = require.resolve('@kbn/babel-preset/istanbul_preset');
 const BABEL_PRESET_PATH = require.resolve('@kbn/babel-preset/webpack_preset');
 
+const nodeModulesButNotKbnPackages = (path: string) => {
+  if (!path.includes('node_modules')) {
+    return false;
+  }
+
+  return !path.includes(`node_modules${Path.sep}@kbn${Path.sep}`);
+};
+
 export function getWebpackConfig(bundle: Bundle, bundleRefs: BundleRefs, worker: WorkerConfig) {
   const ENTRY_CREATOR = require.resolve('./entry_point_creator');
 
@@ -134,7 +142,7 @@ export function getWebpackConfig(bundle: Bundle, bundleRefs: BundleRefs, worker:
         },
         {
           test: /\.scss$/,
-          exclude: /node_modules/,
+          exclude: nodeModulesButNotKbnPackages,
           oneOf: [
             ...worker.themeTags.map((theme) => ({
               resourceQuery: `?${theme}`,
diff --git a/packages/kbn-react-field/BUILD.bazel b/packages/kbn-react-field/BUILD.bazel
new file mode 100644
index 0000000000000..15964ee748f5b
--- /dev/null
+++ b/packages/kbn-react-field/BUILD.bazel
@@ -0,0 +1,119 @@
+load("@npm//@bazel/typescript:index.bzl", "ts_config", "ts_project")
+load("@build_bazel_rules_nodejs//:index.bzl", "js_library", "pkg_npm")
+load("//src/dev/bazel:index.bzl", "jsts_transpiler")
+
+PKG_BASE_NAME = "kbn-react-field"
+PKG_REQUIRE_NAME = "@kbn/react-field"
+
+SOURCE_FILES = glob(
+  [
+    "src/**/*.ts",
+    "src/**/*.tsx",
+    "src/**/*.scss",
+    "src/**/*.svg",
+  ],
+  exclude = [
+    "**/*.test.*",
+    "**/__fixtures__/**",
+    "**/__snapshots__/**",
+  ],
+)
+
+SRCS = SOURCE_FILES
+
+filegroup(
+  name = "srcs",
+  srcs = SRCS,
+)
+
+NPM_MODULE_EXTRA_FILES = [
+  "package.json",
+  "README.md"
+]
+
+RUNTIME_DEPS = [
+  "@npm//prop-types",
+  "@npm//react",
+  "@npm//classnames",
+  "@npm//@elastic/eui",
+  "//packages/kbn-i18n",
+]
+
+TYPES_DEPS = [
+  "//packages/kbn-babel-preset",
+  "//packages/kbn-i18n",
+  "@npm//tslib",
+  "@npm//@types/jest",
+  "@npm//@types/prop-types",
+  "@npm//@types/classnames",
+  "@npm//@types/react",
+  "@npm//@elastic/eui",
+  "@npm//resize-observer-polyfill",
+]
+
+jsts_transpiler(
+  name = "target_webpack",
+  srcs = SRCS,
+  build_pkg_name = package_name(),
+  web = True,
+  additional_args = [
+    "--copy-files",
+    "--quiet"
+  ],
+)
+
+jsts_transpiler(
+  name = "target_node",
+  srcs = SRCS,
+  build_pkg_name = package_name(),
+  additional_args = [
+    "--copy-files",
+    "--quiet"
+  ],
+)
+
+ts_config(
+  name = "tsconfig",
+  src = "tsconfig.json",
+  deps = [
+    "//:tsconfig.base.json",
+    "//:tsconfig.bazel.json",
+  ],
+)
+
+ts_project(
+  name = "tsc_types",
+  args = ['--pretty'],
+  srcs = SRCS,
+  deps = TYPES_DEPS,
+  declaration = True,
+  declaration_map = True,
+  emit_declaration_only = True,
+  out_dir = "target_types",
+  source_map = True,
+  root_dir = "src",
+  tsconfig = ":tsconfig",
+)
+
+js_library(
+  name = PKG_BASE_NAME,
+  srcs = NPM_MODULE_EXTRA_FILES,
+  deps = RUNTIME_DEPS + [":target_node", ":target_webpack", ":tsc_types"],
+  package_name = PKG_REQUIRE_NAME,
+  visibility = ["//visibility:public"],
+)
+
+pkg_npm(
+  name = "npm_module",
+  deps = [
+    ":%s" % PKG_BASE_NAME,
+  ]
+)
+
+filegroup(
+  name = "build",
+  srcs = [
+    ":npm_module",
+  ],
+  visibility = ["//visibility:public"],
+)
diff --git a/packages/kbn-react-field/README.md b/packages/kbn-react-field/README.md
new file mode 100644
index 0000000000000..279c10b3aaecf
--- /dev/null
+++ b/packages/kbn-react-field/README.md
@@ -0,0 +1 @@
+Sharable field type related React components
diff --git a/packages/kbn-react-field/jest.config.js b/packages/kbn-react-field/jest.config.js
new file mode 100644
index 0000000000000..1549cd0071356
--- /dev/null
+++ b/packages/kbn-react-field/jest.config.js
@@ -0,0 +1,13 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+module.exports = {
+  preset: '@kbn/test',
+  rootDir: '../..',
+  roots: ['<rootDir>/packages/kbn-react-field'],
+};
diff --git a/packages/kbn-react-field/package.json b/packages/kbn-react-field/package.json
new file mode 100644
index 0000000000000..3cbfdfa010ba0
--- /dev/null
+++ b/packages/kbn-react-field/package.json
@@ -0,0 +1,9 @@
+{
+  "name": "@kbn/react-field",
+  "main": "./target_node/index.js",
+  "browser": "./target_webpack/index.js",
+  "types": "./target_types/index.d.ts",
+  "version": "1.0.0",
+  "license": "SSPL-1.0 OR Elastic License 2.0",
+  "private": true
+}
\ No newline at end of file
diff --git a/packages/kbn-react-field/src/field_button/__snapshots__/field_button.test.tsx.snap b/packages/kbn-react-field/src/field_button/__snapshots__/field_button.test.tsx.snap
new file mode 100644
index 0000000000000..e65b5fcb8fbbd
--- /dev/null
+++ b/packages/kbn-react-field/src/field_button/__snapshots__/field_button.test.tsx.snap
@@ -0,0 +1,134 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`fieldAction is rendered 1`] = `
+<div
+  className="kbnFieldButton"
+>
+  <button
+    className="kbn-resetFocusState kbnFieldButton__button"
+    onClick={[Function]}
+  >
+    <span
+      className="kbnFieldButton__name"
+    >
+      name
+    </span>
+  </button>
+  <div
+    className="kbnFieldButton__fieldAction"
+  >
+    <span>
+      fieldAction
+    </span>
+  </div>
+</div>
+`;
+
+exports[`fieldIcon is rendered 1`] = `
+<div
+  className="kbnFieldButton"
+>
+  <button
+    className="kbn-resetFocusState kbnFieldButton__button"
+    onClick={[Function]}
+  >
+    <span
+      className="kbnFieldButton__fieldIcon"
+    >
+      <span>
+        fieldIcon
+      </span>
+    </span>
+    <span
+      className="kbnFieldButton__name"
+    >
+      name
+    </span>
+  </button>
+</div>
+`;
+
+exports[`isActive defaults to false 1`] = `
+<div
+  className="kbnFieldButton"
+>
+  <button
+    className="kbn-resetFocusState kbnFieldButton__button"
+    onClick={[Function]}
+  >
+    <span
+      className="kbnFieldButton__name"
+    >
+      name
+    </span>
+  </button>
+</div>
+`;
+
+exports[`isActive renders true 1`] = `
+<div
+  className="kbnFieldButton kbnFieldButton-isActive"
+>
+  <button
+    className="kbn-resetFocusState kbnFieldButton__button"
+    onClick={[Function]}
+  >
+    <span
+      className="kbnFieldButton__name"
+    >
+      name
+    </span>
+  </button>
+</div>
+`;
+
+exports[`isDraggable is rendered 1`] = `
+<div
+  className="kbnFieldButton kbnFieldButton--isDraggable"
+>
+  <button
+    className="kbn-resetFocusState kbnFieldButton__button"
+    onClick={[Function]}
+  >
+    <span
+      className="kbnFieldButton__name"
+    >
+      name
+    </span>
+  </button>
+</div>
+`;
+
+exports[`sizes m is applied 1`] = `
+<div
+  className="kbnFieldButton"
+>
+  <button
+    className="kbn-resetFocusState kbnFieldButton__button"
+    onClick={[Function]}
+  >
+    <span
+      className="kbnFieldButton__name"
+    >
+      name
+    </span>
+  </button>
+</div>
+`;
+
+exports[`sizes s is applied 1`] = `
+<div
+  className="kbnFieldButton kbnFieldButton--small"
+>
+  <button
+    className="kbn-resetFocusState kbnFieldButton__button"
+    onClick={[Function]}
+  >
+    <span
+      className="kbnFieldButton__name"
+    >
+      name
+    </span>
+  </button>
+</div>
+`;
diff --git a/packages/kbn-react-field/src/field_button/field_button.scss b/packages/kbn-react-field/src/field_button/field_button.scss
new file mode 100644
index 0000000000000..f71e097ab7138
--- /dev/null
+++ b/packages/kbn-react-field/src/field_button/field_button.scss
@@ -0,0 +1,76 @@
+.kbnFieldButton {
+  @include euiFontSizeS;
+  border-radius: $euiBorderRadius;
+  margin-bottom: $euiSizeXS;
+  display: flex;
+  align-items: center;
+  transition: box-shadow $euiAnimSpeedFast $euiAnimSlightResistance,
+    background-color $euiAnimSpeedFast $euiAnimSlightResistance; // sass-lint:disable-line indentation
+
+  &:focus-within,
+  &-isActive {
+    @include euiFocusRing;
+  }
+}
+
+.kbnFieldButton--isDraggable {
+  background: lightOrDarkTheme($euiColorEmptyShade, $euiColorLightestShade);
+
+  &:hover,
+  &:focus,
+  &:focus-within {
+    @include euiBottomShadowMedium;
+    border-radius: $euiBorderRadius;
+    z-index: 2;
+  }
+
+  .kbnFieldButton__button {
+    &:hover,
+    &:focus {
+      cursor: grab;
+    }
+  }
+}
+
+.kbnFieldButton__button {
+  flex-grow: 1;
+  text-align: left;
+  padding: $euiSizeS;
+  display: flex;
+  align-items: flex-start;
+  line-height: normal;
+}
+
+.kbnFieldButton__fieldIcon {
+  flex-shrink: 0;
+  line-height: 0;
+  margin-right: $euiSizeS;
+}
+
+.kbnFieldButton__name {
+  flex-grow: 1;
+  word-break: break-word;
+}
+
+.kbnFieldButton__infoIcon {
+  flex-shrink: 0;
+  margin-left: $euiSizeXS;
+}
+
+.kbnFieldButton__fieldAction {
+  margin-right: $euiSizeS;
+}
+
+// Reduce text size and spacing for the small size
+.kbnFieldButton--small {
+  font-size: $euiFontSizeXS;
+
+  .kbnFieldButton__button {
+    padding: $euiSizeXS;
+  }
+
+  .kbnFieldButton__fieldIcon,
+  .kbnFieldButton__fieldAction {
+    margin-right: $euiSizeXS;
+  }
+}
diff --git a/packages/kbn-react-field/src/field_button/field_button.test.tsx b/packages/kbn-react-field/src/field_button/field_button.test.tsx
new file mode 100644
index 0000000000000..e61b41187ba7e
--- /dev/null
+++ b/packages/kbn-react-field/src/field_button/field_button.test.tsx
@@ -0,0 +1,58 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import React from 'react';
+import { shallow } from 'enzyme';
+import { FieldButton, SIZES } from './field_button';
+
+const noop = () => {};
+
+describe('sizes', () => {
+  SIZES.forEach((size) => {
+    test(`${size} is applied`, () => {
+      const component = shallow(<FieldButton onClick={noop} fieldName="name" size={size} />);
+      expect(component).toMatchSnapshot();
+    });
+  });
+});
+
+describe('isDraggable', () => {
+  it('is rendered', () => {
+    const component = shallow(<FieldButton onClick={noop} fieldName="name" isDraggable />);
+    expect(component).toMatchSnapshot();
+  });
+});
+
+describe('fieldIcon', () => {
+  it('is rendered', () => {
+    const component = shallow(
+      <FieldButton onClick={noop} fieldName="name" fieldIcon={<span>fieldIcon</span>} />
+    );
+    expect(component).toMatchSnapshot();
+  });
+});
+
+describe('fieldAction', () => {
+  it('is rendered', () => {
+    const component = shallow(
+      <FieldButton onClick={noop} fieldName="name" fieldAction={<span>fieldAction</span>} />
+    );
+    expect(component).toMatchSnapshot();
+  });
+});
+
+describe('isActive', () => {
+  it('defaults to false', () => {
+    const component = shallow(<FieldButton onClick={noop} fieldName="name" />);
+    expect(component).toMatchSnapshot();
+  });
+  it('renders true', () => {
+    const component = shallow(<FieldButton onClick={noop} fieldName="name" isActive />);
+    expect(component).toMatchSnapshot();
+  });
+});
diff --git a/packages/kbn-react-field/src/field_button/field_button.tsx b/packages/kbn-react-field/src/field_button/field_button.tsx
new file mode 100644
index 0000000000000..4871fea049710
--- /dev/null
+++ b/packages/kbn-react-field/src/field_button/field_button.tsx
@@ -0,0 +1,125 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import './field_button.scss';
+import classNames from 'classnames';
+import React, { ReactNode, HTMLAttributes, ButtonHTMLAttributes } from 'react';
+import { CommonProps } from '@elastic/eui';
+
+export interface FieldButtonProps extends HTMLAttributes<HTMLDivElement> {
+  /**
+   * Label for the button
+   */
+  fieldName: ReactNode;
+  /**
+   * Icon representing the field type.
+   * Recommend using FieldIcon
+   */
+  fieldIcon?: ReactNode;
+  /**
+   * An optional node to place inside and at the end of the <button>
+   */
+  fieldInfoIcon?: ReactNode;
+  /**
+   * An optional node to place outside of and to the right of the <button>
+   */
+  fieldAction?: ReactNode;
+  /**
+   * Adds a forced focus ring to the whole component
+   */
+  isActive?: boolean;
+  /**
+   * Styles the component differently to indicate it is draggable
+   */
+  isDraggable?: boolean;
+  /**
+   * Use the small size in condensed areas
+   */
+  size?: ButtonSize;
+  className?: string;
+  /**
+   * The component will render a `<button>` when provided an `onClick`
+   */
+  onClick?: () => void;
+  /**
+   * Applies to the inner `<button>`  or `<div>`
+   */
+  dataTestSubj?: string;
+  /**
+   * Pass more button props to the `<button>` element
+   */
+  buttonProps?: ButtonHTMLAttributes<HTMLButtonElement> & CommonProps;
+}
+
+const sizeToClassNameMap = {
+  s: 'kbnFieldButton--small',
+  m: null,
+} as const;
+
+export type ButtonSize = keyof typeof sizeToClassNameMap;
+
+export const SIZES = Object.keys(sizeToClassNameMap) as ButtonSize[];
+
+export function FieldButton({
+  size = 'm',
+  isActive = false,
+  fieldIcon,
+  fieldName,
+  fieldInfoIcon,
+  fieldAction,
+  className,
+  isDraggable = false,
+  onClick,
+  dataTestSubj,
+  buttonProps,
+  ...rest
+}: FieldButtonProps) {
+  const classes = classNames(
+    'kbnFieldButton',
+    size ? sizeToClassNameMap[size] : null,
+    { 'kbnFieldButton-isActive': isActive },
+    { 'kbnFieldButton--isDraggable': isDraggable },
+    className
+  );
+
+  const contentClasses = classNames('kbn-resetFocusState', 'kbnFieldButton__button');
+
+  const innerContent = (
+    <>
+      {fieldIcon && <span className="kbnFieldButton__fieldIcon">{fieldIcon}</span>}
+      {fieldName && <span className="kbnFieldButton__name">{fieldName}</span>}
+      {fieldInfoIcon && <div className="kbnFieldButton__infoIcon">{fieldInfoIcon}</div>}
+    </>
+  );
+
+  return (
+    <div className={classes} {...rest}>
+      {onClick ? (
+        <button
+          onClick={(e) => {
+            if (e.type === 'click') {
+              e.currentTarget.focus();
+            }
+            onClick();
+          }}
+          data-test-subj={dataTestSubj}
+          className={contentClasses}
+          {...buttonProps}
+        >
+          {innerContent}
+        </button>
+      ) : (
+        <div className={contentClasses} data-test-subj={dataTestSubj}>
+          {innerContent}
+        </div>
+      )}
+
+      {fieldAction && <div className="kbnFieldButton__fieldAction">{fieldAction}</div>}
+    </div>
+  );
+}
diff --git a/packages/kbn-react-field/src/field_button/index.ts b/packages/kbn-react-field/src/field_button/index.ts
new file mode 100644
index 0000000000000..17c2321c00407
--- /dev/null
+++ b/packages/kbn-react-field/src/field_button/index.ts
@@ -0,0 +1,9 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+export { FieldButton, FieldButtonProps, ButtonSize } from './field_button';
diff --git a/packages/kbn-react-field/src/field_icon/__snapshots__/field_icon.test.tsx.snap b/packages/kbn-react-field/src/field_icon/__snapshots__/field_icon.test.tsx.snap
new file mode 100644
index 0000000000000..f6870a5209c1e
--- /dev/null
+++ b/packages/kbn-react-field/src/field_icon/__snapshots__/field_icon.test.tsx.snap
@@ -0,0 +1,190 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`FieldIcon changes fill when scripted is true 1`] = `
+<EuiToken
+  aria-label="test"
+  className="kbnFieldIcon"
+  fill="dark"
+  iconType="tokenNumber"
+  size="s"
+  title="test"
+/>
+`;
+
+exports[`FieldIcon renders an icon for an unknown type 1`] = `
+<EuiToken
+  aria-label="test"
+  className="kbnFieldIcon"
+  color="gray"
+  iconType="questionInCircle"
+  size="s"
+  title="test"
+/>
+`;
+
+exports[`FieldIcon renders known field types _source is rendered 1`] = `
+<EuiToken
+  aria-label="_source"
+  className="kbnFieldIcon"
+  color="gray"
+  iconType="editorCodeBlock"
+  size="s"
+  title="_source"
+/>
+`;
+
+exports[`FieldIcon renders known field types boolean is rendered 1`] = `
+<EuiToken
+  aria-label="boolean"
+  className="kbnFieldIcon"
+  iconType="tokenBoolean"
+  size="s"
+  title="boolean"
+/>
+`;
+
+exports[`FieldIcon renders known field types conflict is rendered 1`] = `
+<EuiToken
+  aria-label="conflict"
+  className="kbnFieldIcon"
+  color="euiColorVis9"
+  iconType="alert"
+  shape="square"
+  size="s"
+  title="conflict"
+/>
+`;
+
+exports[`FieldIcon renders known field types date is rendered 1`] = `
+<EuiToken
+  aria-label="date"
+  className="kbnFieldIcon"
+  iconType="tokenDate"
+  size="s"
+  title="date"
+/>
+`;
+
+exports[`FieldIcon renders known field types date_range is rendered 1`] = `
+<EuiToken
+  aria-label="date_range"
+  className="kbnFieldIcon"
+  iconType="tokenDate"
+  size="s"
+  title="date_range"
+/>
+`;
+
+exports[`FieldIcon renders known field types geo_point is rendered 1`] = `
+<EuiToken
+  aria-label="geo_point"
+  className="kbnFieldIcon"
+  iconType="tokenGeo"
+  size="s"
+  title="geo_point"
+/>
+`;
+
+exports[`FieldIcon renders known field types geo_shape is rendered 1`] = `
+<EuiToken
+  aria-label="geo_shape"
+  className="kbnFieldIcon"
+  iconType="tokenGeo"
+  size="s"
+  title="geo_shape"
+/>
+`;
+
+exports[`FieldIcon renders known field types ip is rendered 1`] = `
+<EuiToken
+  aria-label="ip"
+  className="kbnFieldIcon"
+  iconType="tokenIP"
+  size="s"
+  title="ip"
+/>
+`;
+
+exports[`FieldIcon renders known field types ip_range is rendered 1`] = `
+<EuiToken
+  aria-label="ip_range"
+  className="kbnFieldIcon"
+  iconType="tokenIP"
+  size="s"
+  title="ip_range"
+/>
+`;
+
+exports[`FieldIcon renders known field types murmur3 is rendered 1`] = `
+<EuiToken
+  aria-label="murmur3"
+  className="kbnFieldIcon"
+  iconType="tokenFile"
+  size="s"
+  title="murmur3"
+/>
+`;
+
+exports[`FieldIcon renders known field types nested is rendered 1`] = `
+<EuiToken
+  aria-label="nested"
+  className="kbnFieldIcon"
+  iconType="tokenNested"
+  size="s"
+  title="nested"
+/>
+`;
+
+exports[`FieldIcon renders known field types number is rendered 1`] = `
+<EuiToken
+  aria-label="number"
+  className="kbnFieldIcon"
+  iconType="tokenNumber"
+  size="s"
+  title="number"
+/>
+`;
+
+exports[`FieldIcon renders known field types number_range is rendered 1`] = `
+<EuiToken
+  aria-label="number_range"
+  className="kbnFieldIcon"
+  iconType="tokenNumber"
+  size="s"
+  title="number_range"
+/>
+`;
+
+exports[`FieldIcon renders known field types string is rendered 1`] = `
+<EuiToken
+  aria-label="string"
+  className="kbnFieldIcon"
+  iconType="tokenString"
+  size="s"
+  title="string"
+/>
+`;
+
+exports[`FieldIcon renders with className if provided 1`] = `
+<EuiToken
+  aria-label="test"
+  className="kbnFieldIcon myClass"
+  color="gray"
+  iconType="questionInCircle"
+  size="s"
+  title="test"
+/>
+`;
+
+exports[`FieldIcon supports same props as EuiToken 1`] = `
+<EuiToken
+  aria-label="test"
+  className="kbnFieldIcon"
+  color="euiColorVis0"
+  fill="none"
+  iconType="tokenNumber"
+  shape="circle"
+  size="l"
+  title="test"
+/>
+`;
diff --git a/packages/kbn-react-field/src/field_icon/field_icon.test.tsx b/packages/kbn-react-field/src/field_icon/field_icon.test.tsx
new file mode 100644
index 0000000000000..cfc67592cd5ea
--- /dev/null
+++ b/packages/kbn-react-field/src/field_icon/field_icon.test.tsx
@@ -0,0 +1,51 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import React from 'react';
+import { shallow } from 'enzyme';
+import { FieldIcon, typeToEuiIconMap } from './field_icon';
+
+const availableTypes = Object.keys(typeToEuiIconMap);
+
+describe('FieldIcon renders known field types', () => {
+  availableTypes.forEach((type) => {
+    test(`${type} is rendered`, () => {
+      const component = shallow(<FieldIcon type={type} />);
+      expect(component).toMatchSnapshot();
+    });
+  });
+});
+
+test('FieldIcon renders an icon for an unknown type', () => {
+  const component = shallow(<FieldIcon type="sdfsdf" label="test" />);
+  expect(component).toMatchSnapshot();
+});
+
+test('FieldIcon supports same props as EuiToken', () => {
+  const component = shallow(
+    <FieldIcon
+      type="number"
+      label="test"
+      color="euiColorVis0"
+      size="l"
+      shape="circle"
+      fill="none"
+    />
+  );
+  expect(component).toMatchSnapshot();
+});
+
+test('FieldIcon changes fill when scripted is true', () => {
+  const component = shallow(<FieldIcon type="number" label="test" scripted={true} />);
+  expect(component).toMatchSnapshot();
+});
+
+test('FieldIcon renders with className if provided', () => {
+  const component = shallow(<FieldIcon type="sdfsdf" label="test" className="myClass" />);
+  expect(component).toMatchSnapshot();
+});
diff --git a/packages/kbn-react-field/src/field_icon/field_icon.tsx b/packages/kbn-react-field/src/field_icon/field_icon.tsx
new file mode 100644
index 0000000000000..cd3c7ee9e7a99
--- /dev/null
+++ b/packages/kbn-react-field/src/field_icon/field_icon.tsx
@@ -0,0 +1,80 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import React from 'react';
+import classNames from 'classnames';
+import { EuiToken, EuiTokenProps } from '@elastic/eui';
+
+export interface FieldIconProps extends Omit<EuiTokenProps, 'iconType'> {
+  type:
+    | 'boolean'
+    | 'conflict'
+    | 'date'
+    | 'date_range'
+    | 'geo_point'
+    | 'geo_shape'
+    | 'ip'
+    | 'ip_range'
+    | 'murmur3'
+    | 'number'
+    | 'number_range'
+    | '_source'
+    | 'string'
+    | string
+    | 'nested';
+  label?: string;
+  scripted?: boolean;
+}
+
+// defaultIcon => a unknown datatype
+const defaultIcon = { iconType: 'questionInCircle', color: 'gray' };
+
+export const typeToEuiIconMap: Partial<Record<string, EuiTokenProps>> = {
+  boolean: { iconType: 'tokenBoolean' },
+  // icon for an index pattern mapping conflict in discover
+  conflict: { iconType: 'alert', color: 'euiColorVis9', shape: 'square' },
+  date: { iconType: 'tokenDate' },
+  date_range: { iconType: 'tokenDate' },
+  geo_point: { iconType: 'tokenGeo' },
+  geo_shape: { iconType: 'tokenGeo' },
+  ip: { iconType: 'tokenIP' },
+  ip_range: { iconType: 'tokenIP' },
+  // is a plugin's data type https://www.elastic.co/guide/en/elasticsearch/plugins/current/mapper-murmur3-usage.html
+  murmur3: { iconType: 'tokenFile' },
+  number: { iconType: 'tokenNumber' },
+  number_range: { iconType: 'tokenNumber' },
+  _source: { iconType: 'editorCodeBlock', color: 'gray' },
+  string: { iconType: 'tokenString' },
+  nested: { iconType: 'tokenNested' },
+};
+
+/**
+ * Field token icon used across the app
+ */
+export function FieldIcon({
+  type,
+  label,
+  size = 's',
+  scripted,
+  className,
+  ...rest
+}: FieldIconProps) {
+  const token = typeToEuiIconMap[type] || defaultIcon;
+
+  return (
+    <EuiToken
+      {...token}
+      className={classNames('kbnFieldIcon', className)}
+      aria-label={label || type}
+      title={label || type}
+      size={size as EuiTokenProps['size']}
+      fill={scripted ? 'dark' : undefined}
+      {...rest}
+    />
+  );
+}
diff --git a/packages/kbn-react-field/src/field_icon/index.ts b/packages/kbn-react-field/src/field_icon/index.ts
new file mode 100644
index 0000000000000..431525fc8e428
--- /dev/null
+++ b/packages/kbn-react-field/src/field_icon/index.ts
@@ -0,0 +1,9 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+export { FieldIcon, FieldIconProps } from './field_icon';
diff --git a/packages/kbn-react-field/src/index.ts b/packages/kbn-react-field/src/index.ts
new file mode 100644
index 0000000000000..af50b139a2918
--- /dev/null
+++ b/packages/kbn-react-field/src/index.ts
@@ -0,0 +1,10 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+export { FieldIconProps, FieldIcon } from './field_icon';
+export { FieldButtonProps, ButtonSize, FieldButton } from './field_button';
diff --git a/packages/kbn-react-field/tsconfig.json b/packages/kbn-react-field/tsconfig.json
new file mode 100644
index 0000000000000..90c8a63c746f1
--- /dev/null
+++ b/packages/kbn-react-field/tsconfig.json
@@ -0,0 +1,23 @@
+{
+  "extends": "../../tsconfig.bazel.json",
+  "compilerOptions": {
+    "declaration": true,
+    "declarationMap": true,
+    "emitDeclarationOnly": true,
+    "outDir": "./target_types",
+    "sourceMap": true,
+    "sourceRoot": "../../../../../packages/kbn-react-field/src",
+    "types": [
+      "jest",
+      "node",
+      "resize-observer-polyfill"
+    ]
+  },
+  "include": [
+    "src/**/*.ts",
+    "src/**/*.tsx",
+  ],
+  "exclude": [
+    "**/__fixtures__/**/*"
+  ]
+}
diff --git a/src/plugins/discover/public/application/apps/main/components/sidebar/discover_field.tsx b/src/plugins/discover/public/application/apps/main/components/sidebar/discover_field.tsx
index 707514073e23e..71b74836ad4fc 100644
--- a/src/plugins/discover/public/application/apps/main/components/sidebar/discover_field.tsx
+++ b/src/plugins/discover/public/application/apps/main/components/sidebar/discover_field.tsx
@@ -23,8 +23,8 @@ import {
 import { i18n } from '@kbn/i18n';
 import { UiCounterMetricType } from '@kbn/analytics';
 import classNames from 'classnames';
+import { FieldIcon, FieldButton } from '@kbn/react-field';
 import { DiscoverFieldDetails } from './discover_field_details';
-import { FieldIcon, FieldButton } from '../../../../../../../kibana_react/public';
 import { FieldDetails } from './types';
 import { IndexPatternField, IndexPattern } from '../../../../../../../data/public';
 import { getFieldTypeName } from './lib/get_field_type_name';
diff --git a/src/plugins/discover/public/application/components/field_name/field_name.tsx b/src/plugins/discover/public/application/components/field_name/field_name.tsx
index 0e8ca31f6379a..47400ebdf0f53 100644
--- a/src/plugins/discover/public/application/components/field_name/field_name.tsx
+++ b/src/plugins/discover/public/application/components/field_name/field_name.tsx
@@ -11,7 +11,7 @@ import './field_name.scss';
 import { EuiBadge, EuiFlexGroup, EuiFlexItem, EuiToolTip } from '@elastic/eui';
 import { FormattedMessage } from '@kbn/i18n/react';
 import { i18n } from '@kbn/i18n';
-import { FieldIcon, FieldIconProps } from '../../../../../kibana_react/public';
+import { FieldIcon, FieldIconProps } from '@kbn/react-field';
 import { getFieldTypeName } from './field_type_name';
 import { IndexPatternField } from '../../../../../data/public';
 import { getFieldSubtypeMulti } from '../../../../../data/common';
diff --git a/src/plugins/kibana_react/public/index.ts b/src/plugins/kibana_react/public/index.ts
index 6fccb804c357f..30fffd57f5987 100644
--- a/src/plugins/kibana_react/public/index.ts
+++ b/src/plugins/kibana_react/public/index.ts
@@ -16,8 +16,6 @@ export * from './context';
 export * from './overview_page';
 export * from './overlays';
 export * from './ui_settings';
-export * from './field_icon';
-export * from './field_button';
 export * from './table_list_view';
 export * from './toolbar_button';
 export * from './split_panel';
diff --git a/x-pack/plugins/canvas/shareable_runtime/webpack.config.js b/x-pack/plugins/canvas/shareable_runtime/webpack.config.js
index dc516060ea360..7db6bf8948f8b 100644
--- a/x-pack/plugins/canvas/shareable_runtime/webpack.config.js
+++ b/x-pack/plugins/canvas/shareable_runtime/webpack.config.js
@@ -18,6 +18,14 @@ const {
 
 const isProd = process.env.NODE_ENV === 'production';
 
+const nodeModulesButNotKbnPackages = (_path) => {
+  if (!_path.includes('node_modules')) {
+    return false;
+  }
+
+  return !_path.includes(`node_modules${path.sep}@kbn${path.sep}`);
+};
+
 module.exports = {
   context: KIBANA_ROOT,
   entry: {
@@ -124,7 +132,7 @@ module.exports = {
       },
       {
         test: /\.scss$/,
-        exclude: [/node_modules/, /\.module\.s(a|c)ss$/],
+        exclude: [nodeModulesButNotKbnPackages, /\.module\.s(a|c)ss$/],
         use: [
           {
             loader: 'style-loader',
diff --git a/x-pack/plugins/graph/public/components/field_manager/field_editor.tsx b/x-pack/plugins/graph/public/components/field_manager/field_editor.tsx
index d4ccfe66dc7d4..aa032060db440 100644
--- a/x-pack/plugins/graph/public/components/field_manager/field_editor.tsx
+++ b/x-pack/plugins/graph/public/components/field_manager/field_editor.tsx
@@ -25,11 +25,11 @@ import {
   EuiIconTip,
 } from '@elastic/eui';
 import { i18n } from '@kbn/i18n';
+import { FieldIcon } from '@kbn/react-field';
 import classNames from 'classnames';
 import { WorkspaceField } from '../../types';
 import { iconChoices } from '../../helpers/style_choices';
 import { LegacyIcon } from '../legacy_icon';
-import { FieldIcon } from '../../../../../../src/plugins/kibana_react/public';
 import { UpdateableFieldProperties } from './field_manager';
 
 import { isEqual } from '../helpers';
diff --git a/x-pack/plugins/graph/public/components/field_manager/field_picker.tsx b/x-pack/plugins/graph/public/components/field_manager/field_picker.tsx
index a764c0241938b..bb451211efd52 100644
--- a/x-pack/plugins/graph/public/components/field_manager/field_picker.tsx
+++ b/x-pack/plugins/graph/public/components/field_manager/field_picker.tsx
@@ -9,8 +9,8 @@ import React, { useState, useEffect, ReactNode } from 'react';
 import { EuiPopover, EuiSelectable, EuiBadge } from '@elastic/eui';
 import { i18n } from '@kbn/i18n';
 import classNames from 'classnames';
+import { FieldIcon } from '@kbn/react-field';
 import { WorkspaceField } from '../../types';
-import { FieldIcon } from '../../../../../../src/plugins/kibana_react/public';
 
 export interface FieldPickerProps {
   fieldMap: Record<string, WorkspaceField>;
diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx
index 9c22ec9d4bb05..db65916ad0754 100644
--- a/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx
+++ b/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx
@@ -36,6 +36,7 @@ import {
   TooltipType,
 } from '@elastic/charts';
 import { i18n } from '@kbn/i18n';
+import { FieldButton } from '@kbn/react-field';
 import type { FieldFormatsStart } from 'src/plugins/field_formats/public';
 import { EuiHighlight } from '@elastic/eui';
 import {
@@ -45,7 +46,6 @@ import {
   Filter,
   esQuery,
 } from '../../../../../src/plugins/data/public';
-import { FieldButton } from '../../../../../src/plugins/kibana_react/public';
 import { ChartsPluginSetup } from '../../../../../src/plugins/charts/public';
 import { DragDrop, DragDropIdentifier } from '../drag_drop';
 import { DatasourceDataPanelProps, DataType } from '../types';
diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/lens_field_icon.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/lens_field_icon.tsx
index edb6957fcf0b2..5bb52a9ba639f 100644
--- a/x-pack/plugins/lens/public/indexpattern_datasource/lens_field_icon.tsx
+++ b/x-pack/plugins/lens/public/indexpattern_datasource/lens_field_icon.tsx
@@ -6,7 +6,7 @@
  */
 
 import React from 'react';
-import { FieldIcon, FieldIconProps } from '../../../../../src/plugins/kibana_react/public';
+import { FieldIcon, FieldIconProps } from '@kbn/react-field';
 import { DataType } from '../types';
 import { normalizeOperationDataType } from './utils';
 
diff --git a/x-pack/plugins/maps/public/classes/sources/mvt_single_layer_vector_source/mvt_field_config_editor.tsx b/x-pack/plugins/maps/public/classes/sources/mvt_single_layer_vector_source/mvt_field_config_editor.tsx
index 77ff783f72e95..9100fd8d9b5d3 100644
--- a/x-pack/plugins/maps/public/classes/sources/mvt_single_layer_vector_source/mvt_field_config_editor.tsx
+++ b/x-pack/plugins/maps/public/classes/sources/mvt_single_layer_vector_source/mvt_field_config_editor.tsx
@@ -16,9 +16,9 @@ import {
   EuiSpacer,
 } from '@elastic/eui';
 import { i18n } from '@kbn/i18n';
+import { FieldIcon } from '@kbn/react-field';
 import _ from 'lodash';
 import { MVTFieldDescriptor } from '../../../../common/descriptor_types';
-import { FieldIcon } from '../../../../../../../src/plugins/kibana_react/public';
 import { MVT_FIELD_TYPE } from '../../../../common/constants';
 
 function makeOption({
diff --git a/x-pack/plugins/maps/public/classes/styles/vector/components/field_select.tsx b/x-pack/plugins/maps/public/classes/styles/vector/components/field_select.tsx
index 74269f39bc36c..8f61bfd35be85 100644
--- a/x-pack/plugins/maps/public/classes/styles/vector/components/field_select.tsx
+++ b/x-pack/plugins/maps/public/classes/styles/vector/components/field_select.tsx
@@ -16,8 +16,8 @@ import {
   EuiFlexItem,
 } from '@elastic/eui';
 import { i18n } from '@kbn/i18n';
+import { FieldIcon } from '@kbn/react-field';
 import { FIELD_ORIGIN, VECTOR_STYLES } from '../../../../../common/constants';
-import { FieldIcon } from '../../../../../../../../src/plugins/kibana_react/public';
 import { StyleField } from '../style_fields_helper';
 
 function renderOption(
diff --git a/x-pack/plugins/maps/public/components/single_field_select.tsx b/x-pack/plugins/maps/public/components/single_field_select.tsx
index 67594db11eb37..8585ed46d3044 100644
--- a/x-pack/plugins/maps/public/components/single_field_select.tsx
+++ b/x-pack/plugins/maps/public/components/single_field_select.tsx
@@ -17,8 +17,8 @@ import {
   EuiFlexItem,
   EuiToolTip,
 } from '@elastic/eui';
+import { FieldIcon } from '@kbn/react-field';
 import { IndexPatternField } from 'src/plugins/data/public';
-import { FieldIcon } from '../../../../../src/plugins/kibana_react/public';
 
 function fieldsToOptions(
   fields?: IndexPatternField[],
diff --git a/x-pack/plugins/maps/public/components/tooltip_selector/add_tooltip_field_popover.tsx b/x-pack/plugins/maps/public/components/tooltip_selector/add_tooltip_field_popover.tsx
index 3804e3873b47e..28cca4b2f6716 100644
--- a/x-pack/plugins/maps/public/components/tooltip_selector/add_tooltip_field_popover.tsx
+++ b/x-pack/plugins/maps/public/components/tooltip_selector/add_tooltip_field_popover.tsx
@@ -21,7 +21,7 @@ import {
 } from '@elastic/eui';
 import { FormattedMessage } from '@kbn/i18n/react';
 import { i18n } from '@kbn/i18n';
-import { FieldIcon } from '../../../../../../src/plugins/kibana_react/public';
+import { FieldIcon } from '@kbn/react-field';
 
 export type FieldProps = {
   label: string;
diff --git a/x-pack/plugins/osquery/public/common/lib/kibana/kibana_react.ts b/x-pack/plugins/osquery/public/common/lib/kibana/kibana_react.ts
index a77ddaee9f250..bd72d4eb91353 100644
--- a/x-pack/plugins/osquery/public/common/lib/kibana/kibana_react.ts
+++ b/x-pack/plugins/osquery/public/common/lib/kibana/kibana_react.ts
@@ -7,6 +7,7 @@
 
 import React from 'react';
 import { useHistory } from 'react-router-dom';
+import { FieldIcon } from '@kbn/react-field';
 import {
   KibanaContextProvider,
   KibanaReactContextValue,
@@ -15,7 +16,6 @@ import {
   useUiSetting$,
   withKibana,
   reactRouterNavigate,
-  FieldIcon,
 } from '../../../../../../../src/plugins/kibana_react/public';
 import { StartServices } from '../../../types';
 
diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/table/field_name_cell.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/table/field_name_cell.tsx
index 327d8d963c75e..4a1cbf34990c8 100644
--- a/x-pack/plugins/security_solution/public/common/components/event_details/table/field_name_cell.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/event_details/table/field_name_cell.tsx
@@ -8,8 +8,8 @@
 import React from 'react';
 import { EuiFlexGroup, EuiFlexItem, EuiBadge, EuiText, EuiToolTip } from '@elastic/eui';
 import { isEmpty } from 'lodash';
+import { FieldIcon } from '@kbn/react-field';
 import * as i18n from '../translations';
-import { FieldIcon } from '../../../../../../../../src/plugins/kibana_react/public';
 import { IndexPatternField } from '../../../../../../../../src/plugins/data/public';
 import { getExampleText } from '../helpers';
 import { BrowserField } from '../../../containers/source';
diff --git a/x-pack/plugins/stack_alerts/public/alert_types/geo_containment/query_builder/util_components/single_field_select.tsx b/x-pack/plugins/stack_alerts/public/alert_types/geo_containment/query_builder/util_components/single_field_select.tsx
index 6fc10da5962ca..715246c801e5c 100644
--- a/x-pack/plugins/stack_alerts/public/alert_types/geo_containment/query_builder/util_components/single_field_select.tsx
+++ b/x-pack/plugins/stack_alerts/public/alert_types/geo_containment/query_builder/util_components/single_field_select.tsx
@@ -14,8 +14,8 @@ import {
   EuiFlexGroup,
   EuiFlexItem,
 } from '@elastic/eui';
+import { FieldIcon } from '@kbn/react-field';
 import { IFieldType } from 'src/plugins/data/public';
-import { FieldIcon } from '../../../../../../../../src/plugins/kibana_react/public';
 
 function fieldsToOptions(fields?: IFieldType[]): Array<EuiComboBoxOptionOption<IFieldType>> {
   if (!fields) {
diff --git a/yarn.lock b/yarn.lock
index e5e2f59359c9f..8af53b75a4bb2 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3828,6 +3828,10 @@
   version "0.0.0"
   uid ""
 
+"@kbn/react-field@link:bazel-bin/packages/kbn-react-field":
+  version "0.0.0"
+  uid ""
+
 "@kbn/rule-data-utils@link:bazel-bin/packages/kbn-rule-data-utils":
   version "0.0.0"
   uid ""