# Input components

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 <Link href="/playground/">playground</Link> as a starting point. You can find the code in our GitHub repository <a href={`${import.meta.env.PUBLIC_GITHUB_URL}/tree/main/playgrounds/solid/src/components`} target="\_blank" rel="noreferrer">here</a>.

## Why input components?

Currently, your fields might look something like this:

```tsx
<Field of={loginForm} path={['email']}>
  {(field) => (
    <div>
      <label for={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/solid';
import { splitProps } from 'solid-js';

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 and use SolidJS's `splitProps` utility to separate the properties of the HTML `<input />` element from the rest.

```tsx
import type { FieldElementProps } from '@formisch/solid';
import { splitProps } from 'solid-js';

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

export function TextInput(props: TextInputProps) {
  const [, inputProps] = splitProps(props, ['input', 'label', 'errors']);
}
```

### JSX code

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

```tsx
import type { FieldElementProps } from '@formisch/solid';
import { splitProps } from 'solid-js';

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

export function TextInput(props: TextInputProps) {
  const [, inputProps] = splitProps(props, ['input', 'label', 'errors']);
  return (
    <div>
      {props.label && (
        <label for={props.name}>
          {props.label} {props.required && <span>*</span>}
        </label>
      )}
      <input
        {...inputProps}
        id={props.name}
        value={props.input ?? ''}
        aria-invalid={!!props.errors}
        aria-errormessage={`${props.name}-error`}
      />
      {props.errors && <div id={`${props.name}-error`}>{props.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/solid';
import { splitProps } from 'solid-js';

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(props: TextInputProps) {
  const [, inputProps] = splitProps(props, ['input', 'label', 'errors']);
  return (
    <div>
      {props.label && (
        <label for={props.name}>
          {props.label} {props.required && <span>*</span>}
        </label>
      )}
      <input
        {...inputProps}
        id={props.name}
        value={props.input ?? ''}
        aria-invalid={!!props.errors}
        aria-errormessage={`${props.name}-error`}
      />
      {props.errors && <div id={`${props.name}-error`}>{props.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.onInput` to update the value programmatically:

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

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

The `field.onInput` method updates the field value and triggers validation. For more details, see the <Link href="/solid/guides/controlled-fields/">controlled fields</Link> guide.

## Next steps

Now that you know how to create reusable input components, continue to the <Link href="/solid/guides/handle-submission/">handle submission</Link> guide to learn how to process form data when the user submits the form.
