import {ExampleCodeBlock, Specifications, SymbolDoc} from '@workday/canvas-kit-docs';
import Basic from './examples/Basic';
import Caution from './examples/Caution';
import Error from './examples/Error';
import Disabled from './examples/Disabled';
import HiddenLabel from './examples/HiddenLabel';
import LabelPositionHorizontalStart from './examples/LabelPositionHorizontalStart';
import LabelPositionHorizontalEnd from './examples/LabelPositionHorizontalEnd';
import RefForwarding from './examples/RefForwarding';
import Required from './examples/Required';
import Custom from './examples/Custom';
import CustomId from './examples/CustomId';
import AllFields from './examples/AllFields';
import Hint from './examples/Hint';
import Grow from './examples/Grow';
import ThemedError from './examples/ThemedErrors';
import GroupedInputs from './examples/GroupedInputs';


# Canvas Kit Form Field

FormField allows users to wrap input components to make them accessible. You can customize the field
by passing in `TextInput`, `Select`, `RadioGroup` and other form elements to `FormField.Input`.

## Installation

```sh
yarn add @workday/canvas-kit-react
```

## Usage

### Basic

Form Field should be used in tandem with most Canvas Kit input components to ensure they meet
accessibility standards. The orientation of the label by default is `vertical`.

<ExampleCodeBlock code={Basic} />

### Error States

Set the `error` prop of the Form Field or define it in the model to indicate it has an error.
`error` accepts the following values:

`"error" | "caution" | undefined`

### Caution

Use the caution state when a value is valid but there is additional information.

<ExampleCodeBlock code={Caution} />

> **Accessibility Note**: Caution state **will not** include the `aria-invalid` attribute on the
> input for screen readers. Use error states when values are not valid.

### Error

Use the error state when the value is no longer valid.

<ExampleCodeBlock code={Error} />

> **Accessibility Note**: Error states include visual color changes to the input border and
> **require** supplemental "error" text for colorblind users to distinguish between fields in an
> error state from fields with standard hint text. Read more about
> [Failure of Success Criterion 1.4.1 due to identifying required or error fields using color differences only](https://www.w3.org/WAI/WCAG22/Techniques/failures/F81)

### Hint

Use `FormField.Hint` to display a short message below the input component and `FormField.Field` to
ensure proper alignment.

<ExampleCodeBlock code={Hint} />

> **Accessibility Note**: Hints are automatically associated to the input field with the
> `aria-describedby` attribute. This ensures that screen readers can automatically announce the hint
> text to users when the input field is focused.

### Disabled

Set the `disabled` prop of `FormField.Input` to prevent users from interacting with it.

<ExampleCodeBlock code={Disabled} />

> **Accessibility Note**: Disabled form elements are exempt from
> [WCAG minimum contrast guidelines](https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html).
> Despite this exemption, disabled fields are more difficult for low vision and colorblind users to
> perceive and may harm the usability of the form. Consider using text elements instead, or
> read-only fields if users cannot modify data.

### Label Position

Set the `orientation` prop of the Form Field to designate the position of the label relative to the
input component. By default, the orientation will be set to `vertical`. If you want your label to be
horizontal, you have two options: `horizontalStart` and `horizontalEnd`.

If you want the position of the label at the start of the container, set orientation prop to
`horizontalStart`.

<ExampleCodeBlock code={LabelPositionHorizontalStart} />

If you want the position of the label at the end of the container, set orientation prop to
`horizontalEnd`.

<ExampleCodeBlock code={LabelPositionHorizontalEnd} />

### Grow

Set the `grow` prop of the Form Field to `true` to configure it (including the wrapped input
component) to expand to the width of its container.

**Note: This Prop is deprecated and will be removed in a future major version.**

<ExampleCodeBlock code={Grow} />

### Ref Forwarding

If you need full customization you can use the `FormField` behavior hooks to build your own
solution. It is also easy it work with custom components or third party libraries and get the CKR
accessibility guarantees by using the `as` prop.

<ExampleCodeBlock code={RefForwarding} />

### Required

Set the `isRequired` prop of the Form Field to `true` to indicate that the field is required. Labels
for required fields are suffixed by a red asterisk.

<ExampleCodeBlock code={Required} />

> **Accessibility Note**: The HTML `required` attribute will be added to the input field and
> announced by screen readers. Consider adding a note at the top of your form indicating that fields
> marked with an asterisk (\*) are required. This provides context for all users.

### Grouped Inputs

Use `FormFieldGroup` when you have a group of inputs that need to be associated to one another, like
`RadioGroup` or a group of `Checkbox`'s. `FormFieldGroup` renders a `fieldset` element and
`FormFieldGroup.Label` renders a `legend` element. These elements will allow screen readers to
automatically announce the legend's context when focusing on the inputs in the group.

`FormFieldGroup` supports the same props of `FormField`:

- `error`: `"caution" | "error"` Defines the error around the whole group of inputs.
- `orientation`: `"horizontal" | "vertical"` Defines the legend placement.
- `isRequired`: `true` Defines if a group like RadioGroup is required.

<ExampleCodeBlock code={GroupedInputs} />

> **Accessibility Note**: In addition to radio button and checkbox groups, `FormFieldGroup` can be
> useful in any situation where the form needs to have multiple sets of identical input fields. For
> example, a form with identical fields for a Shipping address and a Billing address. The legend
> provides critical context for screen reader users in these situations.

### Custom

If you need full customization you can use the `FormField` behavior hooks to build your own
solution. It is also easy it work with custom components or third party libraries and get the CKR
accessibility guarantees by using the `as` prop.

<ExampleCodeBlock code={Custom} />

### Custom id

Form Field will automatically generate an HTML `id` for its input element to link it to the
correponding label. Alternatively, you may set the `id` prop of the Form Field to specify a custom
`id` for the input element. The `id` will be appended by `input-${your-unique-id}`.

<ExampleCodeBlock code={CustomId} />

### All Fields

Form Field should allow you to use it with all `inputs` including `Select`, `TextInput`, `Checkbox`,
`TextArea`, `Switch`, and `RadioGroup`.

<ExampleCodeBlock code={AllFields} />

### Hidden Label

In cases where you want to hide the label while still meeting accessibility standards, you can add
`isHidden` on the `<FormField.Label/>`. This prop will visually hide the label.

<ExampleCodeBlock code={HiddenLabel} />

> **Accessibility Note**: Hidden labels are typically not recommended. In this example, a
> universally recognizable icon like a magnifying glass signaling "search" may be a suitable
> alternative to visible text labels.

### Themed Errors

You can theme your error rings by wrapping an input in a `CanvasProvider` and defining
`focusOutline` and `error` properties on the `theme`.

<ExampleCodeBlock code={ThemedError} />

### Custom Styles

Form Field and its subcomponents support custom styling via the `cs` prop. For more information,
check our
["How To Customize Styles"](https://workday.github.io/canvas-kit/?path=/docs/styling-guides-customizing-styles--docs).

## Accessibility

`FormField` provides essential accessibility features to ensure form inputs are properly labeled and
described for all users, including those using assistive technologies. This section covers both the
technical implementation and best practices for creating accessible forms.

### Label Association

The `FormField` adds a `for` attribute to the `FormField.Label` (`<label>` element) element that
matches the `id` attribute of the `FormField.Input` which is usually a `input` element. This both
labels the input for screen readers and other assistive technology as well as will focus on the
input when the user clicks on the label. If your form field input component is more complicated, the
`FormField` will also add an `id` to the `FormField.Label` and an `aria-labelledby` to the
`FormField.Input` component. You can then forward the `aria-labelledby` to whatever elements you
need for the proper accessibility.

For example, the DOM will look something like this:

```html
<div>
  <label id="label-abc" for="input-abc">First Name</label>
  <input id="input-abc" aria-labelledby="label-abc" />
</div>
```

Some components, like `MultiSelect`, have an additional `role=listbox` element that also needs to
link to the `label` element. The resulting DOM will look something like:

```html
<div>
  <label id="label-abc" for="input-abc">States you've lived in</label>
  <input id="input-abc" aria-labelledby="label-abc" role="combobox" ... />
  <ul role="listbox" aria-labelledby="label-abc">
    <li>Texas</li>
    <li>California</li>
  </ul>
</div>
```

The `MultiSelect` component gets the `aria-labelledby` from the `FormField.Input` and forwards it to
both the `input[role=combobox]` element and the `ul[role=listbox]` element so the screen reader
knows the label for both is "States you've lived in".

### Label Text Best Practices

- **Be Clear and Concise**: Labels should clearly describe the purpose of the input field.
- **Use Visible Labels Instead of Only Placeholders**: Always provide a persistent and accessible
  label with `FormField.Label`. Do not rely solely on placeholder text, as it can disappear while
  typing and may not be accessible to assistive technologies. Use the `isHidden` prop on
  `FormField.Label` if a hidden label is required for visual design.

### Screen Reader Experience

- The label is announced when the input receives focus.
- Required, disabled, and invalid statuses are announced automatically.
- Help text and error messages are announced automatically when focused.
- For grouped inputs, the group label (`legend`) is announced automatically when focused.

## Component API

<SymbolDoc name="FormField" />

## Specifications

<Specifications file="./cypress/component/FormField.spec.tsx" name="FormField" />