# Form Field
> Form Field exposes the elements around form inputs, and an API to compose them.

## Import

```js
import { FormField } from '@gemini-suite/vera-react';

// you may also access Form Field's context via hooks:
// import { useFormFieldContext, useFormField } from '@gemini-suite/vera-react';
```

Form Field is a compound component that consists of multiple parts:

- `FormField.Root`: The wrapper that provides context and functionality for all children.
- `FormField.Label`: The label of a form section. The usage is similar to html label.
- `FormField.HelperText`: The message that assists the user in completing the form field that requires additional context.
- `FormField.FeedbackMessage`: The validation feedback message that shows up when the field is flagged during validation.

## Examples

### Basic

It's encouraged to use `FormField` alongside all standalone form components like `TextInput`, as every input must have a corresponding label to be accessible to assistive technology.

```jsx
<FormField.Root as={Flex} flow="column">
  <FormField.Label>{'Field label'}</FormField.Label>
  <TextInput />
  <FormField.HelperText>{`This is a hint about how this field works.`}</FormField.HelperText>
</FormField.Root>
```

### Labeling

Make sure that each text field is accompanied by a `FormField.Label`. Effective form labeling helps users understand what information to enter into a text input.

<Callout variant="tip">

`FormField` automatically connects the label, help text, and validation message to the input element for assistive technology using [context](https://reactjs.org/docs/context.html), so you don't need to provide additional props such as `id` and `htmlFor`.

</Callout>

```jsx
() => {
  const [selectedCountry, setSelectedCountry] = React.useState();

  return (
    <Flex flow="column" gap="spacingM">
      <FormField.Root as={Flex} flow="column">
        <FormField.Label>{'Name'}</FormField.Label>
        <TextInput />
      </FormField.Root>
      <FormField.Root as={Flex} flow="column">
        <FormField.Label>{'Country'}</FormField.Label>
        <Select
          placeholder="Select country"
          value={selectedCountry}
          onChange={setSelectedCountry}
          options={[
            { value: 'no', label: 'Norway' },
            { value: 'pl', label: 'Poland' }
          ]}
        />
      </FormField.Root>
    </Flex>
  );
};
```

There may be occasions where the label is apparent through context to sighted users, so you wish to omit it from the view. We still need a label attached to the input for assistive technology, in these cases you can provide the `.is-hiddenVisually` className:

```jsx
<FormField.Root>
  <FormField.Label className="is-hiddenVisually">{'Name'}</FormField.Label>
  <TextInput />
</FormField.Root>
```

### Helper text

Offer helper text to give the user further instructional content.

```jsx
<FormField.Root as={Flex} flow="column">
  <FormField.Label>{'Name'}</FormField.Label>
  <TextInput />
  <FormField.HelperText>{'Hint: your first name.'}</FormField.HelperText>
</FormField.Root>
```

Helper text can be used to address concerns that users may have.
For example, an e-mail input can provide a hint to clarify usage of the e-mail:

```jsx
<FormField.Root as={Flex} flow="column">
  <FormField.Label>{'Email address'}</FormField.Label>
  <TextInput />
  <FormField.HelperText>{`We'll never share your email.`}</FormField.HelperText>
</FormField.Root>
```

### Contextual tooltip

An info button with contextual help [Tooltip](/components/tooltip) or [Popover](/components/popover) may be placed next to field's label to provide additional information.

```jsx
<Flex flow="column">
  <FormField.Root as={Flex} flow="column">
    <Flex gap="spacingXs">
      <FormField.Label>{'Medium'}</FormField.Label>
      <Tooltip
        content="Additional information or help about a text field."
        delay={0}
      >
        <Button withLoneIcon size="xSmall" variant="ghost">
          <SvgIcon iconName="info" />
        </Button>
      </Tooltip>
    </Flex>
    <TextInput placeholder="Example input" />
  </FormField.Root>
  <FormField.Root as={Flex} flow="column" size="small">
    <Flex gap="none">
      <FormField.Label>{'Small'}</FormField.Label>
      <Tooltip
        size="small"
        content="Additional information or help about a text field."
        delay={0}
      >
        <Button withLoneIcon size="xxSmall" variant="ghost">
          <SvgIcon iconName="info" />
        </Button>
      </Tooltip>
    </Flex>
    <TextInput placeholder="Example input" />
  </FormField.Root>
</Flex>
```

### Making a field disabled

By passing the `isDisabled` prop, the input has `disabled` set to `true`.

```jsx
<FormField.Root isDisabled>
  <Flex flow="column" gap="spacingXs">
    <FormField.Label>{'Name'}</FormField.Label>
    <TextInput />
  </Flex>
</FormField.Root>
```

### Making a field required

By passing the `isRequired` prop, the input has `aria-required` set to `true`, and the `FormField.Label` will show a red asterisk.

```jsx
<FormField.Root isRequired size="small">
  <Flex flow="column" gap="spacingXs">
    <FormField.Label>{'Name'}</FormField.Label>
    <TextInput />
  </Flex>
</FormField.Root>
```

### Validation status

`FormField` provides interface for showing a feedback message based on the `validationStatus`.
`FormField.FeedbackMessage` will only show up when the `validationStatus` is provided.
Keep `FormField.FeedbackMessage` concise and simple.

<Callout variant="tip">

`FormField.FeedbackMessage` is automatically associated with the input for assistive technology.

</Callout>

```jsx
<Flex flow="column" gap="spacingM">
  <FormField.Root validationStatus="error" as={Flex} flow="column">
    <FormField.Label>{'Invalid field'}</FormField.Label>
    <TextInput />
    <FormField.FeedbackMessage>
      <FormField.FeedbackIcon />
      {
        'Inform the user how their input violates the requirements of the field.'
      }
    </FormField.FeedbackMessage>
  </FormField.Root>
  <FormField.Root validationStatus="success" as={Flex} flow="column">
    <FormField.Label>{'Valid field'}</FormField.Label>
    <TextInput />
    <FormField.FeedbackMessage>
      <FormField.FeedbackIcon />
      {'Inform the user that their input is valid/successful.'}
    </FormField.FeedbackMessage>
  </FormField.Root>
</Flex>
```

#### Interactive validation

Provide clear and useful error messages that help the user fix the issue. Error messages should be displayed in a timely manner — typically when the form is submitted or once the field loses focus (on blur).

<Callout variant="tip">

Validating a form field when the user leaves the current field can be helpful, but it can also be potentially frustrating to users who tab through controls to navigate a page. Prefer validating field on form submission whenever it makes sense.

</Callout>

```jsx
() => {
  const [value, setValue] = React.useState('');
  const [isError, setIsError] = React.useState(false);

  const hasSufficientLength = inputValue => inputValue.length >= 20;

  const handleInputChange = e => {
    setValue(e.currentTarget.value);
  };
  const handleInputBlur = () => {
    setIsError(!hasSufficientLength(value));
  };

  React.useEffect(() => {
    if (isError && hasSufficientLength(value)) {
      setIsError(false);
    }
  }, [isError, value]);

  return (
    <FormField.Root
      validationStatus={isError ? 'error' : undefined}
      as={Flex}
      flow="column"
    >
      <FormField.Label>Password</FormField.Label>
      <TextInput
        type="password"
        value={value}
        onChange={handleInputChange}
        onBlur={handleInputBlur}
      />
      {!isError ? (
        <FormField.HelperText>
          Password should be long and avoid common phrases.
        </FormField.HelperText>
      ) : (
        <FormField.FeedbackMessage>
          <FormField.FeedbackIcon />
          Password is too short! You need 20+ characters.
        </FormField.FeedbackMessage>
      )}
    </FormField.Root>
  );
};
```

<Callout variant="tip">

Error messages should be removed as early as possible, ideally as the user is typing, so that the user can see when an error has been addressed.

</Callout>

```jsx
() => {
  const [value, setValue] = React.useState('mona lisa');
  const doesValueContainSpaces = inputValue => /\s/g.test(inputValue);
  const [validationStatus, setValidationStatus] = React.useState();
  const handleInputChange = e => {
    setValue(e.currentTarget.value);
  };

  React.useEffect(() => {
    if (doesValueContainSpaces(value)) {
      setValidationStatus('error');
    } else if (value) {
      setValidationStatus('success');
    } else {
      setValidationStatus(undefined);
    }
  }, [value]);

  return (
    <FormField.Root validationStatus={validationStatus} as={Flex} flow="column">
      <FormField.Label>{'Nickname'}</FormField.Label>
      <TextInput value={value} onChange={handleInputChange} />
      <FormField.FeedbackMessage>
        <FormField.FeedbackIcon />
        {validationStatus === 'error' && 'Nickname cannot contain spaces.'}
        {validationStatus === 'success' && 'Valid nickname!'}
      </FormField.FeedbackMessage>
    </FormField.Root>
  );
};
```

### Field elements layout

You can render `<FormField>` as one of the layout component, for example [Flex](/components/layout/flex). Then you can pass any props `Flex` supports, for example to specify flow direction. This gives you full control over field's layout.

```jsx
<FormField.Root
  as={Flex}
  flow={{
    '@initial': 'column',
    '@mqLargeAndUp': 'row'
  }}
  cross="baseline"
  gap={{
    '@initial': 'spacingXs',
    '@mqLargeAndUp': 'spacingM'
  }}
>
  <FlexItem flex="none">
    <FormField.Label>{'Your name'}</FormField.Label>
  </FlexItem>
  <FlexItem grow="1">
    <Flex flow="column" gap="spacingXs">
      <TextInput />
      <FormField.HelperText>
        {'Real name will help your friends to find you!'}
      </FormField.HelperText>
    </Flex>
  </FlexItem>
</FormField.Root>
```

### Sizes

`FormField` comes with two sizes ‐ `medium` and `small`, with the `medium` size used by default. Size is propagated to all `FormField` parts such as `FormField.Label` or `FormField.HelperText`.

<Callout variant="tip">

The size of the `FormField` is also inherited by all basic form elements like `TextInput`, `TextArea`, `Checkbox`, `Radio` and `Select`.

</Callout>

```jsx
<Flex flow="column">
  <FormField.Root size="small" as={Flex} flow="column">
    <FormField.Label>{'Small'}</FormField.Label>
    <TextInput placeholder="Placeholder" />
    <FormField.HelperText>{'Helper text'}</FormField.HelperText>
  </FormField.Root>
  <FormField.Root size="medium" as={Flex} flow="column">
    <FormField.Label>{'Medium'}</FormField.Label>
    <TextInput placeholder="Placeholder" />
    <FormField.HelperText>{'Helper text'}</FormField.HelperText>
  </FormField.Root>
</Flex>
```

#### Multi-sizing

Vera provides `applySizes` utility, which lets you specify size "scopes" within your app.
If you want to change the size of all form fields within a container, you can apply the sizes to the container
instead of each `FormField` separately.
Size still can be overwritten on a per-field basis.

```jsx
<Flex
  gap="spacingS"
  className={applySizes({
    control: 'small'
  })}
  flow="column"
>
  <FormField.Root as={Flex} flow="column">
    <FormField.Label as="span">Checkbox label</FormField.Label>
    <Checkbox.Root value="a">
      <Checkbox.Indicator />
      <Checkbox.Label>Choice A</Checkbox.Label>
    </Checkbox.Root>
  </FormField.Root>
  <FormField.Root as={Flex} flow="column">
    <FormField.Label>{'TextInput label'}</FormField.Label>
    <TextInput placeholder="Placeholder" />
    <FormField.HelperText>{'Helper text'}</FormField.HelperText>
  </FormField.Root>
  <FormField.Root as={Flex} flow="column">
    <FormField.Label>{'Select label'}</FormField.Label>
    <Select
      placeholder="Select"
      value="a"
      options={[
        { value: 'a', label: 'Option A' },
        { value: 'b', label: 'Option B' }
      ]}
    />
    <FormField.HelperText>{'Helper text'}</FormField.HelperText>
  </FormField.Root>
  <FormField.Root as={Flex} flow="column" validationStatus="error">
    <FormField.Label>{'Textarea label'}</FormField.Label>
    <Textarea />
    <FormField.FeedbackMessage>
      <FormField.FeedbackIcon /> {'Required.'}
    </FormField.FeedbackMessage>
  </FormField.Root>
</Flex>
```

### With checkbox or radio groups

When providing a top-level label for a group of inputs where each individual input already has a label, such as a radio or checkbox button group, overwrite the `as` prop of the `FormField.Label` to `span`.

<Callout variant="tip">

Under the hood, `FormField.Label` will be configured to label the group via `aria-labelledby`.

</Callout>

```jsx
<FormField.Root as={Flex} flow="column">
  <FormField.Label as="span">Multiple choice list</FormField.Label>
  <CheckboxGroup>
    <Flex flow="column" gap="spacingXs">
      <Checkbox.Root value="a">
        <Checkbox.Indicator />
        <Checkbox.Label>Choice A</Checkbox.Label>
      </Checkbox.Root>
      <Checkbox.Root value="b">
        <Checkbox.Indicator />
        <Checkbox.Label>Choice B</Checkbox.Label>
      </Checkbox.Root>
      <Checkbox.Root value="c">
        <Checkbox.Indicator />
        <Checkbox.Label>Choice C</Checkbox.Label>
      </Checkbox.Root>
    </Flex>
  </CheckboxGroup>
</FormField.Root>
```

### Intergration with form libraries

`FormField` is designed to easily integrate with external form libraries, such as [React Hook Form](https://react-hook-form.com/), when you need to manage complex form state and validation.

Check example below to see how to wire `FormField` and input components with [React Hook Form](https://react-hook-form.com/). The example uses [valibot](https://github.com/fabian-hiller/valibot) schema library for validation, but you can use any schema library or custom validation logic.

<Card
  href="https://next--698f15fa99e7b146f9002f64.chromatic.com/?path=/story/demos-form--default"
  title="See form demo in Storybook"
  actionIcon="externalLink"
/>

---

## Accessibility features

<ul>
  <li iconName="check">

`FormField.FormLabel` will have `htmlFor` that points to the `id` of the form input.

  </li>
  <li iconName="check">

`FormField.FeedbackMessage` adds `aria-describedby` and `aria-invalid` pointing to the form input.

  </li>
  <li iconName="check">

`FormField.HelperText` adds/extends `aria-describedby` pointing to the form input.

  </li>

</ul>

---

## API Reference

### FormField.Root

| Name               | Type                                                      | Default | Description                                                                                                                                                                                                                                                                                  | Required |
| ------------------ | --------------------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `as`               | `keyof JSX.IntrinsicElements \| React.ComponentType<any>` | `div`   | Change the component to a different HTML tag or custom component. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.   For more details, read our [Composition](/get-started/composition#polymorphism) guide. |          |
| `css`              | `StitchesCss`                                             |         | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries, or variants.                                                |          |
| `isRequired`       | `boolean`                                                 | `false` | When `true`, form field is marked as required. The `FormField.RequiredIndicator` is visible. `required` and `aria-required` props are passed to the form element.                                                                                                                            |          |
| `isDisabled`       | `boolean`                                                 | `false` | When `true`, the form field will be disabled. `disabled` prop is passed to the form element.                                                                                                                                                                                                 |          |
| `isReadOnly`       | `boolean`                                                 | `false` | When `true`, the form field will be readonly. `readonly` and `aria-readonly` props are passed to the form element.                                                                                                                                                                           |          |
| `validationStatus` | `"error" \| "success" \| "warning"`                       |         | Field validation status. The form element as well as `FormField.FeedbackMessage` and `FormField.FeedbackIcon` styles will be styled to match the status.                                                                                                                                     |          |
| `size`             | `"small" \| "medium"`                                     |         | The size of the form field.                                                                                                                                                                                                                                                                  |          |
| `id`               | `string`                                                  |         | Used for aria attributes and various element ID suffixes. Defaults to a generated ID.                                                                                                                                                                                                        |          |

### FormField.Label

<Callout variant="tip">

In addition to the props below, you can pass [Text props](/components/typography/text#api-reference).

</Callout>

| Name                | Type                                                      | Default | Description                                                                                                                                                                                                                                                                                  | Required |
| ------------------- | --------------------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `as`                | `keyof JSX.IntrinsicElements \| React.ComponentType<any>` | `label` | Change the component to a different HTML tag or custom component. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.   For more details, read our [Composition](/get-started/composition#polymorphism) guide. |          |
| `css`               | `StitchesCss`                                             |         | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries, or variants.                                                |          |
| `requiredIndicator` | `React.ReactElement`                                      |         | If added, the label will use this element as indicator of required field.                                                                                                                                                                                                                    |          |

### FormField.RequiredIndicator

| Name  | Type          | Default | Description                                                                                                                                                                                                                                   | Required |
| ----- | ------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `css` | `StitchesCss` |         | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries, or variants. |          |

### FormField.HelperText

<Callout variant="tip">

In addition to the props below, you can pass [Text props](/components/typography/text#api-reference).

</Callout>

| Name  | Type          | Default | Description                                                                                                                                                                                                                                   | Required |
| ----- | ------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `css` | `StitchesCss` |         | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries, or variants. |          |

### FormField.FeedbackMessage

<Callout variant="tip">

In addition to the props below, you can pass [Text props](/components/typography/text#api-reference).

</Callout>

| Name  | Type          | Default | Description                                                                                                                                                                                                                                   | Required |
| ----- | ------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `css` | `StitchesCss` |         | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries, or variants. |          |

### FormField.FeedbackIcon

| Name          | Type                                                      | Default   | Description                                                                                                                                                                                                                                                                                  | Required |
| ------------- | --------------------------------------------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `as`          | `keyof JSX.IntrinsicElements \| React.ComponentType<any>` | `div`     | Change the component to a different HTML tag or custom component. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.   For more details, read our [Composition](/get-started/composition#polymorphism) guide. |          |
| `css`         | `StitchesCss`                                             |           | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries or variants.                                                 |          |
| `iconName`    | `IconToken`                                               |           | The name of the icon to display. When missing, icon is based on the `validationStatus`.                                                                                                                                                                                                      |          |
| `size`        | `"small" \| "medium" \| "large" \| "xLarge"`              | `"small"` | The size of the icon.                                                                                                                                                                                                                                                                        |          |
| `pathData`    | `string \| string[]`                                      |           | Path of a custom SVG to display.                                                                                                                                                                                                                                                             |          |
| `svgSize`     | `number`                                                  |           | The size of the visible area of the icon, called `viewBox`. Expands to `0 0 ${svgSize} ${svgSize}` which is a square.                                                                                                                                                                        |          |
| `strokeWidth` | `number`                                                  |           | Width of the stroke to be applied to the icon shape.                                                                                                                                                                                                                                         |          |
