Gecko UIGecko UI

RHFController

Core wrapper component for React Hook Form integration

RHFController

RHFController is a wrapper around React Hook Form's Controller component that automatically injects the control prop from FormProvider. This is the foundation for all RHF* components in Gecko UI.

Installation

import { RHFController } from '@geckoui/geckoui';

Basic Usage

import { useForm, FormProvider } from 'react-hook-form';
import { RHFController } from '@geckoui/geckoui';

function Example() {
  const methods = useForm({
    defaultValues: {
      email: ''
    }
  });

  return (
    <FormProvider {...methods}>
      <form onSubmit={methods.handleSubmit(console.log)}>
        <RHFController
          name="email"
          render={({ field }) => (
            <input
              {...field}
              type="email"
              placeholder="Enter email"
            />
          )}
        />
      </form>
    </FormProvider>
  );
}

Props API

Accepts all props from React Hook Form's Controller:

PropTypeDefaultDescription
namestring-Field name (required)
controlControlAuto-injectedOptional: Pass explicitly for nested forms or custom form context
renderfunction-Render prop function (required)
defaultValueany-Default field value
shouldUnregisterbooleanfalseUnregister field on unmount

About control prop: By default, RHFController uses useFormContext() to get the control object automatically. Pass it explicitly when you have nested FormProviders and want to connect to a specific form instance.

Why Use RHFController?

Without RHFController (Standard RHF)

import { Controller, useFormContext } from 'react-hook-form';

function CustomInput() {
  const { control } = useFormContext();

  return (
    <Controller
      control={control}  // Must manually get and pass control
      name="email"
      render={({ field }) => <input {...field} />}
    />
  );
}

With RHFController (Gecko UI)

import { RHFController } from '@geckoui/geckoui';

function CustomInput() {
  return (
    <RHFController
      name="email"  // control is auto-injected!
      render={({ field }) => <input {...field} />}
    />
  );
}

Examples

Access Form State

<RHFController
  name="password"
  render={({ field, fieldState, formState }) => (
    <div>
      <input {...field} type="password" />
      {fieldState.error && (
        <span>{fieldState.error.message}</span>
      )}
      {formState.isDirty && <span>Unsaved changes</span>}
    </div>
  )}
/>

Custom Component Integration

<RHFController
  name="birthDate"
  render={({ field }) => (
    <CustomDatePicker
      value={field.value}
      onChange={field.onChange}
      onBlur={field.onBlur}
    />
  )}
/>

Nested FormProviders

When you have nested forms, pass control explicitly to specify which form:

function NestedFormsExample() {
  const outerForm = useForm({ defaultValues: { outerField: '' } });
  const innerForm = useForm({ defaultValues: { innerField: '' } });

  return (
    <FormProvider {...outerForm}>
      <FormProvider {...innerForm}>
        {/* Uses innerForm's control automatically */}
        <RHFController
          name="innerField"
          render={({ field }) => <input {...field} />}
        />

        {/* Explicitly use outerForm's control */}
        <RHFController
          name="outerField"
          control={outerForm.control}
          render={({ field }) => <input {...field} />}
        />
      </FormProvider>
    </FormProvider>
  );
}

When to Use

Use RHFController When:

  • Building custom form components
  • Integrating third-party libraries
  • Need fine-grained control over field behavior

Use Pre-built RHF Components When:

  • Working with Gecko UI components
  • Want automatic error styling
  • Need less boilerplate