diff --git a/.changeset/olive-bears-act.md b/.changeset/olive-bears-act.md
new file mode 100644
index 00000000000..9a56a789ba9
--- /dev/null
+++ b/.changeset/olive-bears-act.md
@@ -0,0 +1,109 @@
+---
+'@primer/react': major
+---
+
+The `FormControl` component will be used to deprecate the `FormGroup`, `InputField`, and `ChoiceInputField` components. It has the ability to render contextual content with your inputs: labels, validation statuses, captions. It also handles the ARIA attributes that make the form controls accessible to assistive technology.
+
+
+
+| Before | After |
+
+
+|
+
+```jsx
+import {FormControl, Checkbox, TextInput} from "@primer/react"
+
+
+
+ Example text
+
+
+
+// OR
+
+
+ Example text
+
+
+
+// OR
+
+
+ Example text
+
+
+
+```
+
+ |
+
+
+```jsx
+import {FormGroup, TextInput} from "@primer/react"
+
+
+ Example text
+
+
+
+// OR
+
+
+ Example text
+
+
+
+```
+
+ |
+
+
+|
+
+```jsx
+import {InputField} from '@primer/react'
+
+ Example text
+
+
+```
+
+ |
+
+
+```jsx
+import {FormControl} from '@primer/react'
+
+ Example Text
+
+
+```
+
+ |
+
+
+
+| Migration steps to FormControl |
+
+|
+
+Upgrade to the new `FormControl` component by referring to the [examples in our documentation](https://primer.style/react/FormControl).
+
+or
+
+Continue using the deprecated `FormGroup`, `ChoiceInputField` or `InputField` :
+
+```js
+import {FormGroup, ChoiceInputField, InputField} from '@primer/react/deprecated' // change your import statements
+```
+
+Codemods:
+
+- InputField codemod: https://github.com/primer/react-migrate/blob/main/src/use-deprecated-inputfield.js
+- ChoiceInputField https://github.com/primer/react-migrate/blob/main/src/use-deprecated-choiceinputfield.js
+- FormGroup codemod: https://github.com/primer/react-migrate/blob/main/src/use-deprecated-formgroup.js
+
+ |
+
+
diff --git a/docs/content/FormGroup.md b/docs/content/deprecated/FormGroup.md
similarity index 98%
rename from docs/content/FormGroup.md
rename to docs/content/deprecated/FormGroup.md
index 7ed49c395af..143c750db0e 100644
--- a/docs/content/FormGroup.md
+++ b/docs/content/deprecated/FormGroup.md
@@ -12,7 +12,7 @@ Use [FormControl](/FormControl) instead.
## Default example
-```jsx live
+```jsx live deprecated
<>
Example text
diff --git a/docs/content/InputField.mdx b/docs/content/deprecated/InputField.mdx
similarity index 96%
rename from docs/content/InputField.mdx
rename to docs/content/deprecated/InputField.mdx
index d92ce7cbb91..6da7689f800 100644
--- a/docs/content/InputField.mdx
+++ b/docs/content/deprecated/InputField.mdx
@@ -7,7 +7,7 @@ source: https://github.com/primer/react/blob/main/src/InputField/InputField.tsx
storybook: '/react/storybook?path=/story/forms-inputfield--text-input-field'
---
-import {InputField, TextInputWithTokens, Autocomplete, Select} from '@primer/react'
+import {TextInputWithTokens, Autocomplete, Select} from '@primer/react'
## Deprecation
@@ -17,7 +17,7 @@ Use [FormControl](/FormControl) instead.
### Basic
-```jsx live
+```jsx live deprecated
Name
@@ -26,7 +26,7 @@ Use [FormControl](/FormControl) instead.
### Required
-```jsx live
+```jsx live deprecated
Name
@@ -35,7 +35,7 @@ Use [FormControl](/FormControl) instead.
### Disabled
-```jsx live
+```jsx live deprecated
Name
@@ -44,7 +44,7 @@ Use [FormControl](/FormControl) instead.
### Using different input components
-```javascript live noinline
+```javascript live noinline deprecated
const TextInputWithTokensExample = () => {
const [tokens, setTokens] = React.useState([
{text: 'zero', id: 0},
@@ -115,7 +115,7 @@ Every input must have a corresponding label to be accessible to assistive techno
-```jsx live
+```jsx live deprecated
Name
@@ -124,7 +124,7 @@ Every input must have a corresponding label to be accessible to assistive techno
### With a caption
-```jsx live
+```jsx live deprecated
Name
@@ -134,7 +134,7 @@ Every input must have a corresponding label to be accessible to assistive techno
### With validation
-```javascript live noinline
+```javascript live noinline deprecated
const ValidationExample = () => {
const [value, setValue] = React.useState('mona lisa')
const [validationResult, setValidationResult] = React.useState()
diff --git a/docs/src/@primer/gatsby-theme-doctocat/nav.yml b/docs/src/@primer/gatsby-theme-doctocat/nav.yml
index c50f7f70dd0..1ece7688ddd 100644
--- a/docs/src/@primer/gatsby-theme-doctocat/nav.yml
+++ b/docs/src/@primer/gatsby-theme-doctocat/nav.yml
@@ -164,9 +164,11 @@
- title: Flex
url: /deprecated/Flex
- title: FormGroup
- url: /FormGroup
+ url: /deprecated/FormGroup
- title: Grid
url: /deprecated/Grid
+ - title: InputField
+ url: /deprecated/InputField
- title: Position
url: /deprecated/Position
- title: SelectMenu
diff --git a/src/ChoiceInputField.tsx b/src/ChoiceInputField.tsx
index dc329766fba..d3369e55550 100644
--- a/src/ChoiceInputField.tsx
+++ b/src/ChoiceInputField.tsx
@@ -1,11 +1,11 @@
import React from 'react'
import {Box, Checkbox, Radio, useSSRSafeId} from '.'
import {get} from './constants'
-import {Slots} from './InputField/slots'
+import {Slots} from './deprecated/InputField/slots'
import ChoiceInputLeadingVisual from './_ChoiceInputLeadingVisual'
-import InputField, {Props as InputFieldProps} from './InputField/InputField'
+import InputField, {Props as InputFieldProps} from './deprecated/InputField/InputField'
import {FormValidationStatus} from './utils/types/FormValidationStatus'
-import InputFieldCaption from './InputField/_InputFieldCaption'
+import InputFieldCaption from './deprecated/InputField/_InputFieldCaption'
export interface Props extends Pick {
/**
diff --git a/src/_ChoiceInputLeadingVisual.tsx b/src/_ChoiceInputLeadingVisual.tsx
index beecb6e32ea..912b70cf787 100644
--- a/src/_ChoiceInputLeadingVisual.tsx
+++ b/src/_ChoiceInputLeadingVisual.tsx
@@ -1,5 +1,5 @@
import React from 'react'
-import {Slot} from './InputField/slots'
+import {Slot} from './deprecated/InputField/slots'
const ChoiceInputLeadingVisual: React.FC = ({children}) => {children}
diff --git a/src/__tests__/FormGroup.types.test.tsx b/src/__tests__/FormGroup.types.test.tsx
index 5ed40fddaed..c35f16d3bd1 100644
--- a/src/__tests__/FormGroup.types.test.tsx
+++ b/src/__tests__/FormGroup.types.test.tsx
@@ -1,5 +1,5 @@
import React from 'react'
-import FormGroup from '../FormGroup'
+import FormGroup from '../deprecated/FormGroup'
export function shouldAcceptCallWithNoProps() {
return
diff --git a/src/__tests__/FormGroup.test.tsx b/src/__tests__/deprecated/FormGroup.test.tsx
similarity index 86%
rename from src/__tests__/FormGroup.test.tsx
rename to src/__tests__/deprecated/FormGroup.test.tsx
index d9f5b5b223e..af68927a7b2 100644
--- a/src/__tests__/FormGroup.test.tsx
+++ b/src/__tests__/deprecated/FormGroup.test.tsx
@@ -1,6 +1,6 @@
import React from 'react'
-import {FormGroup} from '..'
-import {behavesAsComponent, checkExports} from '../utils/testing'
+import FormGroup from '../../deprecated/FormGroup'
+import {behavesAsComponent, checkExports} from '../../utils/testing'
import {render as HTMLRender, cleanup} from '@testing-library/react'
import {axe, toHaveNoViolations} from 'jest-axe'
import 'babel-polyfill'
@@ -9,7 +9,7 @@ expect.extend(toHaveNoViolations)
describe('FormGroup', () => {
behavesAsComponent({Component: FormGroup})
- checkExports('FormGroup', {
+ checkExports('deprecated/FormGroup', {
default: FormGroup
})
diff --git a/src/__tests__/InputField.test.tsx b/src/__tests__/deprecated/InputField.test.tsx
similarity index 98%
rename from src/__tests__/InputField.test.tsx
rename to src/__tests__/deprecated/InputField.test.tsx
index 8cb06947a47..48ccec4443f 100644
--- a/src/__tests__/InputField.test.tsx
+++ b/src/__tests__/deprecated/InputField.test.tsx
@@ -2,7 +2,8 @@ import React from 'react'
import {render, cleanup} from '@testing-library/react'
import {axe, toHaveNoViolations} from 'jest-axe'
import 'babel-polyfill'
-import {Autocomplete, InputField, SSRProvider, TextInput, TextInputWithTokens} from '..'
+import {Autocomplete, SSRProvider, TextInput, TextInputWithTokens} from '../../'
+import InputField from '../../deprecated/InputField'
expect.extend(toHaveNoViolations)
const TEXTINPUTFIELD_LABEL_TEXT = 'Name'
diff --git a/src/__tests__/__snapshots__/FormGroup.test.tsx.snap b/src/__tests__/deprecated/__snapshots__/FormGroup.test.tsx.snap
similarity index 100%
rename from src/__tests__/__snapshots__/FormGroup.test.tsx.snap
rename to src/__tests__/deprecated/__snapshots__/FormGroup.test.tsx.snap
diff --git a/src/FormGroup.tsx b/src/deprecated/FormGroup.tsx
similarity index 65%
rename from src/FormGroup.tsx
rename to src/deprecated/FormGroup.tsx
index 4ecd657a62a..83dfbfaacec 100644
--- a/src/FormGroup.tsx
+++ b/src/deprecated/FormGroup.tsx
@@ -1,7 +1,7 @@
import styled from 'styled-components'
-import {get} from './constants'
-import sx, {SxProp} from './sx'
-import {ComponentProps} from './utils/types'
+import {get} from '../constants'
+import sx, {SxProp} from '../sx'
+import {ComponentProps} from '../utils/types'
const FormGroup = styled.div`
margin: ${get('space.3')} 0;
@@ -9,6 +9,7 @@ const FormGroup = styled.div`
${sx};
`
+/** @deprecated Use FormControl instead. See https://primer.style/react/FormControl for more details. */
const FormGroupLabel = styled.label`
display: block;
margin: 0 0 ${get('space.2')};
@@ -21,4 +22,5 @@ FormGroupLabel.displayName = 'FormGroup.Label'
export type FormGroupProps = ComponentProps
export type FormGroupLabelProps = ComponentProps
+/** @deprecated Use FormControl instead. See https://primer.style/react/FormControl for more details. */
export default Object.assign(FormGroup, {Label: FormGroupLabel})
diff --git a/src/InputField/InputField.tsx b/src/deprecated/InputField/InputField.tsx
similarity index 93%
rename from src/InputField/InputField.tsx
rename to src/deprecated/InputField/InputField.tsx
index 32c780bfe2a..2aeb961d22b 100644
--- a/src/InputField/InputField.tsx
+++ b/src/deprecated/InputField/InputField.tsx
@@ -1,13 +1,13 @@
import React from 'react'
-import {Autocomplete, Box, Select, TextInput, TextInputWithTokens, useSSRSafeId} from '..'
-import InputValidation from '../_InputValidation'
-import {ComponentProps} from '../utils/types'
-import {FormValidationStatus} from '../utils/types/FormValidationStatus'
+import {Autocomplete, Box, Select, TextInput, TextInputWithTokens, useSSRSafeId} from '../../'
+import InputValidation from '../../_InputValidation'
+import {ComponentProps} from '../../utils/types'
+import {FormValidationStatus} from '../../utils/types/FormValidationStatus'
import InputFieldCaption from './_InputFieldCaption'
import InputFieldLabel from './_InputFieldLabel'
import InputFieldValidation from './_InputFieldValidation'
import {Slots} from './slots'
-import ValidationAnimationContainer from '../_ValidationAnimationContainer'
+import ValidationAnimationContainer from '../../_ValidationAnimationContainer'
export interface Props> {
children?: React.ReactNode
/**
@@ -40,6 +40,7 @@ export interface InputFieldContext
validationMessageId: string
}
+/** @deprecated Use FormControl instead. See https://primer.style/react/FormControl for more details. */
const InputField = >({
children,
disabled,
diff --git a/src/InputField/_InputFieldCaption.tsx b/src/deprecated/InputField/_InputFieldCaption.tsx
similarity index 89%
rename from src/InputField/_InputFieldCaption.tsx
rename to src/deprecated/InputField/_InputFieldCaption.tsx
index 1a67ccc6e59..9e39a68de12 100644
--- a/src/InputField/_InputFieldCaption.tsx
+++ b/src/deprecated/InputField/_InputFieldCaption.tsx
@@ -1,5 +1,5 @@
import React from 'react'
-import InputCaption from '../_InputCaption'
+import InputCaption from '../../_InputCaption'
import {InputFieldContext} from './InputField'
import {Slot} from './slots'
diff --git a/src/InputField/_InputFieldLabel.tsx b/src/deprecated/InputField/_InputFieldLabel.tsx
similarity index 92%
rename from src/InputField/_InputFieldLabel.tsx
rename to src/deprecated/InputField/_InputFieldLabel.tsx
index 10b27710226..843234da761 100644
--- a/src/InputField/_InputFieldLabel.tsx
+++ b/src/deprecated/InputField/_InputFieldLabel.tsx
@@ -1,5 +1,5 @@
import React from 'react'
-import InputLabel from '../_InputLabel'
+import InputLabel from '../../_InputLabel'
import {InputFieldContext} from './InputField'
import {Slot} from './slots'
diff --git a/src/InputField/_InputFieldValidation.tsx b/src/deprecated/InputField/_InputFieldValidation.tsx
similarity index 100%
rename from src/InputField/_InputFieldValidation.tsx
rename to src/deprecated/InputField/_InputFieldValidation.tsx
diff --git a/src/InputField/index.ts b/src/deprecated/InputField/index.ts
similarity index 100%
rename from src/InputField/index.ts
rename to src/deprecated/InputField/index.ts
diff --git a/src/InputField/slots.ts b/src/deprecated/InputField/slots.ts
similarity index 63%
rename from src/InputField/slots.ts
rename to src/deprecated/InputField/slots.ts
index 1df9b0ed419..4418ab896c6 100644
--- a/src/InputField/slots.ts
+++ b/src/deprecated/InputField/slots.ts
@@ -1,3 +1,3 @@
-import createSlots from '../utils/create-slots'
+import createSlots from '../../utils/create-slots'
export const {Slots, Slot} = createSlots(['Caption', 'Input', 'Label', 'LeadingVisual'])
diff --git a/src/deprecated/index.ts b/src/deprecated/index.ts
index 37376d8d88a..3075abb1cd9 100644
--- a/src/deprecated/index.ts
+++ b/src/deprecated/index.ts
@@ -22,6 +22,9 @@ export type {
DropdownItemProps,
DropdownMenuProps
} from '../Dropdown'
+export {default as FormGroup} from './FormGroup'
+export type {FormGroupProps, FormGroupLabelProps} from './FormGroup'
+export {default as InputField} from './InputField'
export {default as SelectMenu} from '../SelectMenu'
export type {
SelectMenuProps,
diff --git a/src/index.ts b/src/index.ts
index a7a4d6663b3..fa26067008a 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -96,13 +96,10 @@ export type {FilterListProps, FilterListItemProps} from './FilterList'
export {default as Flash} from './Flash'
export type {FlashProps} from './Flash'
export {default as FormControl} from './FormControl'
-export {default as FormGroup} from './FormGroup'
-export type {FormGroupProps, FormGroupLabelProps} from './FormGroup'
export {default as Header} from './Header'
export type {HeaderProps, HeaderItemProps, HeaderLinkProps} from './Header'
export {default as Heading} from './Heading'
export type {HeadingProps} from './Heading'
-export {default as InputField} from './InputField'
export {default as LabelGroup} from './LabelGroup'
export type {LabelGroupProps} from './LabelGroup'
export {default as Label} from './Label'