# FormField

> Wires a label, help text and error message to any Stance form control.

Category: Forms · Status: stable · Package: @bindshq/stance-react@0.1.1 · Docs: https://stanceui.com/components/form-field

FormField is the standard wrapper for a single form control. It renders the label, description and error and passes ids and ARIA state to the control through context, so every Stance input, select, checkbox, switch, slider and file upload is labelled and described correctly with no manual id plumbing.

## Import

```tsx
import { FormField } from '@bindshq/stance-react';
```

Styles are imported once per app: `@bindshq/stance-tokens/css` and `@bindshq/stance-react/styles.css`.

## Examples

### Basic

```tsx
import { FormField, Input } from '@bindshq/stance-react';

export function Basic() {
  return (
    <div style={{ width: '100%', maxWidth: 380 }}>
      <FormField label="Full name" description="As it should appear on signed documents." required>
        <Input autoComplete="name" />
      </FormField>
    </div>
  );
}
```

### Validation

An error marks the control aria-invalid and is announced via role="alert".

```tsx
import { FormField, Input } from '@bindshq/stance-react';

export function Validation() {
  return (
    <div style={{ width: '100%', maxWidth: 380 }}>
      <FormField label="Signer email" error="Enter an email address like name@company.com" required>
        <Input type="email" defaultValue="priya@" />
      </FormField>
    </div>
  );
}
```

### Horizontal layout

Label beside the control on wide screens; stacks on phones.

```tsx
import { FormField, Input } from '@bindshq/stance-react';

export function Horizontal() {
  return (
    <div style={{ display: 'grid', gap: 16, width: '100%', maxWidth: 640 }}>
      <FormField
        label="Display name"
        orientation="horizontal"
        description="Visible to your organisation."
      >
        <Input defaultValue="Acme Legal" />
      </FormField>
      <FormField label="Department" orientation="horizontal" optionalText="Optional">
        <Input />
      </FormField>
    </div>
  );
}
```

### With other controls

```tsx
import { Checkbox, FormField, NativeSelect, Textarea } from '@bindshq/stance-react';

export function AnyControl() {
  return (
    <div style={{ display: 'grid', gap: 16, width: '100%', maxWidth: 380 }}>
      <FormField label="Default template">
        <NativeSelect
          options={[
            { value: 'classic', label: 'Classic' },
            { value: 'minimal', label: 'Minimal' },
          ]}
        />
      </FormField>
      <FormField label="Disclaimer" description="Appended below every signature.">
        <Textarea rows={3} />
      </FormField>
      <FormField label="Accept the data processing terms" error="You must accept to continue">
        <Checkbox />
      </FormField>
    </div>
  );
}
```

## API reference

| Component | Prop | Type | Default | Description |
| --- | --- | --- | --- | --- |
| FormField | `label` | `ReactNode` | None | Visible label, associated with the control. |
| FormField | `description` | `ReactNode` | None | Help text, linked via aria-describedby. |
| FormField | `error` | `ReactNode` | None | Error message. Its presence marks the field invalid. |
| FormField | `required` | `boolean` | `false` | Adds a required indicator and sets required on the control. |
| FormField | `optionalText` | `ReactNode` | None | Marker for optional fields, e.g. "Optional". |
| FormField | `disabled` | `boolean` | `false` | Disables the control. |
| FormField | `readOnly` | `boolean` | `false` | Makes the control read-only. |
| FormField | `id` | `string` | None | Explicit id for the control; generated otherwise. |
| FormField | `orientation` | `'vertical' \| 'horizontal'` | `'vertical'` | Label above or beside the control. |
| FormField | `hideLabel` | `boolean` | `false` | Visually hides the label but keeps it accessible. |
| useFormFieldControl | `(props) => props` | `hook` | None | Merges field state into your own custom control’s props. |

## Accessibility

- The label is a real <label for>, so clicking it focuses or toggles the control.
- Description and error are both referenced by aria-describedby, in that order.
- Errors render with role="alert" so they are announced when they appear.
- The required indicator is decorative; ", required" is announced through visually hidden text.
- Errors carry an icon as well as colour, so they are not communicated by colour alone.

## Guidelines

**Do**

- Use one FormField per control.
- Write errors that say how to fix the problem.

**Don’t**

- Nest FormFields.
- Use FormField around a CheckboxGroup or RadioGroup. They render their own fieldset and legend.

## Related

- https://stanceui.com/components/input
- https://stanceui.com/components/label
- https://stanceui.com/components/checkbox-group
- https://stanceui.com/components/radio-group
