# Input components

> This document is the Markdown version of [formisch.dev/react/guides/input-components/](https://formisch.dev/react/guides/input-components/). For the complete documentation index, see [llms.txt](https://formisch.dev/llms.txt).

To make your code more readable, we recommend that you develop your own input components if you are not using a prebuilt UI library. There you can encapsulate logic to display error messages, for example.

> If you're already a bit more experienced, you can use the input components we developed for our [playground](/playground/login/) as a starting point. You can find the code in our GitHub repository [here](https://github.com/open-circle/formisch/tree/main/playgrounds/react/src/components).

## Why input components?

Currently, your fields might look something like this:

```tsx
<Field of={loginForm} path={['email']}>
  {(field) => (
    <div>
      <label htmlFor={field.props.name}>Email</label>
      <input
        {...field.props}
        id={field.props.name}
        value={field.input}
        type="email"
        required
      />
      {field.errors && <div>{field.errors[0]}</div>}
    </div>
  )}
</Field>
```

If CSS and a few more functionalities are added here, the code quickly becomes confusing. In addition, you have to rewrite the same code for almost every form field.

Our goal is to develop a `TextInput` component so that the code ends up looking like this:

```tsx
<Field of={loginForm} path={['email']}>
  {(field) => (
    <TextInput
      {...field.props}
      type="email"
      label="Email"
      input={field.input}
      errors={field.errors}
      required
    />
  )}
</Field>
```

## Create an input component

In the first step, you create a new file for the `TextInput` component and, if you use TypeScript, define its properties.

```tsx
import type { FieldElementProps } from '@formisch/react';

interface TextInputProps extends FieldElementProps {
  type: 'text' | 'email' | 'tel' | 'password' | 'url' | 'date';
  label?: string;
  placeholder?: string;
  input: string | undefined;
  errors: [string, ...string[]] | null;
  required?: boolean;
}
```

### Component function

In the next step, add the component function to the file. We can destructure props directly and spread the remaining props.

```tsx
import type { FieldElementProps } from '@formisch/react';

interface TextInputProps extends FieldElementProps {
  /* ... */
}

export function TextInput({ label, input, errors, ...props }: TextInputProps) {
  // Component implementation
}
```

### JSX code

After that, you can add the JSX code to the return statement.

```tsx
import type { FieldElementProps } from '@formisch/react';

interface TextInputProps extends FieldElementProps {
  /* ... */
}

export function TextInput({ label, input, errors, ...props }: TextInputProps) {
  const { name, required } = props;
  return (
    <div>
      {label && (
        <label htmlFor={name}>
          {label} {required && <span>*</span>}
        </label>
      )}
      <input
        {...props}
        name={name}
        id={name}
        required={required}
        value={input ?? ''}
        aria-invalid={!!errors}
        aria-errormessage={`${name}-error`}
      />
      {errors && <div id={`${name}-error`}>{errors[0]}</div>}
    </div>
  );
}
```

### Next steps

You can now build on this code and add CSS, for example. You can also follow the procedure to create other components such as `Checkbox`, `Slider`, `Select` and `FileInput`.

### Final code

Below is an overview of the entire code of the `TextInput` component.

```tsx
import type { FieldElementProps } from '@formisch/react';

interface TextInputProps extends FieldElementProps {
  type: 'text' | 'email' | 'tel' | 'password' | 'url' | 'date';
  label?: string;
  placeholder?: string;
  input: string | undefined;
  errors: [string, ...string[]] | null;
  required?: boolean;
}

export function TextInput({ label, input, errors, ...props }: TextInputProps) {
  const { name, required } = props;
  return (
    <div>
      {label && (
        <label htmlFor={name}>
          {label} {required && <span>*</span>}
        </label>
      )}
      <input
        {...props}
        name={name}
        id={name}
        required={required}
        value={input ?? ''}
        aria-invalid={!!errors}
        aria-errormessage={`${name}-error`}
      />
      {errors && <div id={`${name}-error`}>{errors[0]}</div>}
    </div>
  );
}
```

## Using component libraries

When using component libraries that don't expose their underlying native HTML elements, you cannot spread `field.props` directly. Instead, use `field.onChange` to update the value programmatically:

```tsx
import { DatePicker } from 'some-component-library';

<Field of={form} path={['date']}>
  {(field) => (
    <DatePicker
      value={field.input}
      onChange={(newDate) => field.onChange(newDate)}
    />
  )}
</Field>;
```

The `field.onChange` method updates the field value and triggers validation. For more details, see the [controlled fields](/react/guides/controlled-fields.md) guide.

For ready-made wiring recipes, check out our integration guides:

- [shadcn/ui](/react/guides/shadcn-ui.md)
- [Ark UI](/react/guides/ark-ui.md)
- [Base UI](/react/guides/base-ui.md)
- [Chakra UI](/react/guides/chakra-ui.md)
- [Mantine](/react/guides/mantine.md)
- [React Aria](/react/guides/react-aria.md)

## Next steps

Now that you know how to create reusable input components, continue to the [handle submission](/react/guides/handle-submission.md) guide to learn how to process form data when the user submits the form.
