# Input components

> This document is the Markdown version of [formisch.dev/qwik/guides/input-components/](https://formisch.dev/qwik/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/qwik/src/components).

## Why input components?

Currently, your fields might look something like this:

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

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']}
  render$={(field) => (
    <TextInput
      {...field.props}
      type="email"
      label="Email"
      input={field.input}
      errors={field.errors}
      required
    />
  )}
/>
```

## 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/qwik';
import { component$, type ReadonlySignal } from '@qwik.dev/core';

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

### Component function

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

```tsx
import type { FieldElementProps } from '@formisch/qwik';
import { component$, type ReadonlySignal } from '@qwik.dev/core';

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

export const TextInput = component$<TextInputProps>(
  ({ input, label, errors, ...props }) => {
    // Component JSX will go here
  }
);
```

### JSX code

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

```tsx
import type { FieldElementProps } from '@formisch/qwik';
import { component$, type ReadonlySignal } from '@qwik.dev/core';

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

export const TextInput = component$<TextInputProps>(
  ({ input, label, errors, ...props }) => {
    const { name, required } = props;
    return (
      <div>
        {label && (
          <label for={name}>
            {label} {required && <span>*</span>}
          </label>
        )}
        <input
          {...props}
          id={name}
          value={input.value}
          aria-invalid={!!errors.value}
          aria-errormessage={`${name}-error`}
        />
        {errors.value && <div id={`${name}-error`}>{errors.value[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/qwik';
import { component$, type ReadonlySignal } from '@qwik.dev/core';

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

export const TextInput = component$<TextInputProps>(
  ({ input, label, errors, ...props }) => {
    const { name, required } = props;
    return (
      <div>
        {label && (
          <label for={name}>
            {label} {required && <span>*</span>}
          </label>
        )}
        <input
          {...props}
          id={name}
          value={input.value}
          aria-invalid={!!errors.value}
          aria-errormessage={`${name}-error`}
        />
        {errors.value && <div id={`${name}-error`}>{errors.value[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']}
  render$={(field) => (
    <DatePicker
      value={field.input.value}
      onChange$={(newDate) => field.onInput(newDate)}
    />
  )}
/>;
```

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

## Next steps

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