Skip to main content

Your opinion matters! Together with you, we want to continuously improve KoliBri. Share your ideas, wishes, or suggestions—quickly and easily.

React Hook Form

The package @public-ui/react-hook-form-adapter connects the form library with the React components from @public-ui/react-v19. For each form component there is a controller component that uses the React Hook Form internally. Value, error message, touched and disabled state are passed to the KoliBri component automatically.

Installation​

npm i @public-ui/react-hook-form-adapter react-hook-form

The adapter requires the following peer dependencies:

PackageVersion
@public-ui/componentssame version as the adapter
@public-ui/react-v19same version as the adapter
react19.x
react-hook-form7.x

Setting up KoliBri itself (registering a theme, loading the components) is described under Frameworks.

Available controllers​

ComponentControllerBound property
KolComboboxKolComboboxController_value
KolInputCheckboxKolInputCheckboxController_checked
KolInputColorKolInputColorController_value
KolInputDateKolInputDateController_value
KolInputEmailKolInputEmailController_value
KolInputFileKolInputFileController–
KolInputNumberKolInputNumberController_value
KolInputPasswordKolInputPasswordController_value
KolInputRadioKolInputRadioController_value
KolInputRangeKolInputRangeController_value
KolInputTextKolInputTextController_value
KolSelectKolSelectController_value
KolSingleSelectKolSingleSelectController_value
KolTextareaKolTextareaController_value

The adapter also exports the API types of the components (InputTextAPI, SelectAPI, InputCheckboxAPI …).

Usage​

A controller accepts the properties of the React Hook Form Controller and all properties of the respective KoliBri component:

PropertyMeaning
nameName of the field in the form, also passed to the component as _name
controlThe control object from useForm()
rulesReact Hook Form validation rules (required, min, pattern, validate …)
defaultValueInitial value of the field if it is not part of the defaultValues of useForm()
shouldUnregisterRemoves the value from the form when the field unmounts
_label, _hint …All other properties are passed to the KoliBri component unchanged

The following example shows a form with two fields. To submit, handleSubmit is called in the onSubmit event of KolForm:

import { KolInputCheckboxController, KolInputTextController } from '@public-ui/react-hook-form-adapter';
import { KolButton, KolForm } from '@public-ui/react-v19';
import type { BaseSyntheticEvent } from 'react';
import { useForm, type SubmitHandler } from 'react-hook-form';

interface FormData {
firstName: string;
termsAccepted: boolean | null;
}

export const MyForm = () => {
const { control, handleSubmit } = useForm<FormData>({
defaultValues: { firstName: '', termsAccepted: false },
mode: 'onTouched',
});

const onSubmit: SubmitHandler<FormData> = (data) => {
console.log(data);
};

return (
<KolForm
_on={{
onSubmit: (event) => {
void handleSubmit(onSubmit)(event as unknown as BaseSyntheticEvent);
},
}}
>
<KolInputTextController
name="firstName"
control={control}
rules={{ required: 'Please enter your first name.' }}
_label="First name"
_required
/>
<KolInputCheckboxController
name="termsAccepted"
control={control}
rules={{ required: 'Please accept the terms of use.' }}
_label="I accept the terms of use"
_required
/>
<KolButton _label="Submit" _type="submit" />
</KolForm>
);
};

A complete example using all controllers can be found in the .

What the adapter takes care of​

The controller sets the following properties of the KoliBri component itself. If they are also set manually, the adapter overrides them.

PropertyValue
_value or _checkedCurrent value of the field (see Available controllers)
_nameValue of name
_msgOn a validation error { _type: 'error', _description: <error message> }, otherwise undefined
_touchedtrue as soon as React Hook Form marks the field as touched (fieldState.isTouched)
_disabledDisabled state from React Hook Form (field.disabled)

The adapter also connects the component's events with React Hook Form:

  • onInput and onChange write the value into the form. The form value is therefore up to date while the user is typing.
  • onBlur marks the field as touched.
  • Your own handlers in _on are kept and called afterwards.
  • The element reference is passed to React Hook Form. With shouldFocusError, React Hook Form focuses the first invalid field on submit. Your own ref is served as well.

Notes​

Error messages appear only after the field was touched​

KoliBri only shows _msg when the field is considered touched (_touched). The adapter takes this state from React Hook Form. However, handleSubmit does not mark fields as touched. If a form is submitted without the user visiting the fields, validation fails but the error messages stay invisible.

The React sample solves this by marking all fields as touched and validating again in the error case:

const { control, handleSubmit, setValue, getValues, trigger } = useForm<FormData>({
defaultValues,
mode: 'onTouched',
shouldFocusError: true,
});

const onError = () => {
(Object.keys(defaultValues) as Array<keyof FormData>).forEach((name) => {
setValue(name, getValues(name), { shouldTouch: true, shouldValidate: true });
});
void trigger(undefined, { shouldFocus: true });
};

// <KolForm _on={{ onSubmit: (event) => void handleSubmit(onSubmit, onError)(event as unknown as BaseSyntheticEvent) }}>

Always provide error messages as text​

The adapter shows the message of the React Hook Form error. For rules without their own message (e.g. required: true or min: 0) it is empty, and the component shows [object Object] instead. Therefore provide a message for every rule:

rules={{
required: 'Please enter your age.',
min: { value: 0, message: 'The age must not be negative.' },
}}

Custom messages via _msg are not possible​

Since the adapter always sets _msg, a manually set _msg is overridden. Use _hint for permanent hints on a field.

Disabling fields​

Disable a field with _disabled. The adapter passes the value on to React Hook Form. React Hook Form . The controller's disabled property is not evaluated. Use useForm({ disabled: true }) to disable all fields of a form at once.

Example with two fields of which only one can be filled:

const { control, watch } = useForm({ defaultValues: { first: '', second: '' } });

<KolInputTextController name="first" control={control} _label="First field" _disabled={!!watch('second')} />
<KolInputTextController name="second" control={control} _label="Second field" _disabled={!!watch('first')} />

Checkbox​

  • The controller binds the field value to _checked. A checked checkbox returns its _value (default: true), an unchecked checkbox returns null, not false. Take this into account in the form type (boolean | null).
  • _checked only accepts boolean values. Therefore do not change _value on KolInputCheckboxController, otherwise the field value cannot be written back to the component.

File selection​

KolInputFileController reads the selected files into the form as a FileList but does not write a value back to the component. defaultValues, setValue and reset therefore do not change what the component displays.