# 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/svelte/src/components`} target="\_blank" rel="noreferrer">here</a>.

## Why input components?

Currently, your fields might look something like this:

```svelte
<Field of={loginForm} path={['email']}>
  {#snippet children(field)}
    <div>
      <label for={field.props.name}>Email</label>
      <input
        {...field.props}
        id={field.props.name}
        value={field.input}
        type="email"
        required
      />
      {#if field.errors}
        <div>{field.errors[0]}</div>
      {/if}
    </div>
  {/snippet}
</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:

```svelte
<Field of={loginForm} path={['email']}>
  {#snippet children(field)}
    <TextInput
      {...field.props}
      type="email"
      label="Email"
      input={field.input}
      errors={field.errors}
      required
    />
  {/snippet}
</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.

```svelte
<script lang="ts">
  import type { FieldElementProps } from '@formisch/svelte';

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

  let {
    type = 'text',
    label,
    placeholder,
    input,
    errors,
    ...props
  } = $props<TextInputProps>();
</script>
```

### Component markup

In the next step, add the component markup to display the input and error messages.

```svelte
<script lang="ts">
  // ... types and props definition ...
</script>

<div>
  {#if label}
    <label for={props.name}>
      {label}
      {#if props.required}<span>*</span>{/if}
    </label>
  {/if}
  <input
    {...props}
    {type}
    {placeholder}
    id={props.name}
    value={input}
    aria-invalid={!!errors}
    aria-errormessage={`${props.name}-error`}
  />
  {#if errors}
    <div id={`${props.name}-error`}>{errors[0]}</div>
  {/if}
</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.

```svelte
<script lang="ts">
  import type { FieldElementProps } from '@formisch/svelte';

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

  let {
    type = 'text',
    label,
    placeholder,
    input,
    errors,
    ...props
  } = $props<TextInputProps>();
</script>

<div>
  {#if label}
    <label for={props.name}>
      {label}
      {#if props.required}<span>*</span>{/if}
    </label>
  {/if}
  <input
    {...props}
    {type}
    {placeholder}
    id={props.name}
    value={input}
    aria-invalid={!!errors}
    aria-errormessage={`${props.name}-error`}
  />
  {#if errors}
    <div id={`${props.name}-error`}>{errors[0]}</div>
  {/if}
</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:

```svelte
<script>
  import { DatePicker } from 'some-component-library';
</script>

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

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

## Next steps

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