Custom form controls

If for some reason you're not using an HTML5 input, select or textarea element as an input, you have two options:

Using helpers

The more straightforward way would be to use any of the returned helpers from useForm for handling inputs.

import { useForm } from '@felte/react';

export function Form() {
  const { form, setFields } = useForm({
    initialValues: {
      customControlName: '',
    },
    // ...
  });

  function handleChange(event) {
    setFields('customControlName', event.detail.value, true);
  }

  return (
    <form ref={form}>
      <SomeCustomControl onCustomChangeEvent={handleChange} />
    </form>
  );
}

If your custom form control uses an input or other native form control behind the scenes, you may dispatch an input or change event from it when the value of it changes (if your control does not do this already). Felte listens to change events for <input type="checkbox">, <input type="radio">, <select> and <input type="file"> elements; and for input events on any other type of input.

Using useField

You might want to create a shareable component that should work with Felte without needing to use any of the helpers. If said component uses a native HTML control, and your user interacts directly with it, then assigning a name to it should be enough for Felte to manage it. But there might be situations on which the control itself is completely custom made, maybe using an input[type="hidden"] behind the scenes or not using a native control at all (e.g. a contenteditable div). For this situations you can use useField.

useField provides you with some helpers to make your custom control visible to Felte without needing to use any of useForm's helpers. Its usage looks something like:

import React from 'react';
import { useField } from '@felte/react';

function CustomInput({ name, labelId }) {
  const { field, onChange, onBlur } = useField(name);

  function handleChange(e) {
    onChange(e.currentTarget.innerText);
  }

  return (
    <div
      ref={field}
      onInput={handleChange}
      onBlur={onBlur}
      aria-labelledby={labelId}
      role="textbox"
      contentEditable
      tabIndex={0}
    />
  );
}

The previous component will behave just like a regular input when used within a form managed by Felte. Only requiring a name prop.

useField can be called in two different ways:

The options accepted by useField are:

useField returns an object with the following properties:

NOTE: when creating custom controls like this, be mindful of the accessibility of your component. Handling proper keyboard interactions, roles and labels is a must for your custom control to be seen as an input by assistive technologies.