react-hook-form-bound single-value picker with a searchable text input. Wraps the @uxf/ui/combobox primitive and manages its value, isInvalid, and helperText from form state.
Use @uxf/form/combobox for a single-choice, type-to-filter picker (or server-loaded options) inside a @uxf/form form — it registers the field with react-hook-form via control/name and renders validation errors automatically. For a standalone, manually-controlled combobox (outside a form), use the @uxf/ui/combobox twin directly.
@uxf/form/select.@uxf/form/multi-combobox.import { Combobox, ComboboxValue } from "@uxf/form/combobox";
import { Form } from "@uxf/form/form";
import { useForm } from "react-hook-form";
interface FormData {
country: ComboboxValue<string>;
}
const options = [
{ id: "cz", label: "Czechia" },
{ id: "sk", label: "Slovakia" },
];
function Example() {
const formApi = useForm<FormData>({ defaultValues: { country: null } });
return (
<Form formApi={formApi} id="example" onSubmit={(values) => console.log(values)}>
<Combobox
control={formApi.control}
isRequired
label="Country"
name="country"
options={options}
placeholder="Search..."
/>
</Form>
);
}
Async options — pass loadOptions instead of options; the returned promise supplies the list and local filtering is skipped:
<Combobox control={formApi.control} label="Country" loadOptions={(query) => fetchCountries(query)} name="country" />
The react-hook-form value is the selected option object ({ id, label }) or null — the same shape as the @uxf/ui/combobox twin (ComboboxValue<Id> = { id, label } | null). No normalisation happens beyond coercing undefined to null before handing the value to the twin.
ComboboxProps<FormData> = ControlProps<FormData> + the visual props of the @uxf/ui/combobox twin (minus the ones this field manages: inputGroupRef, inputRef, inputWrapperRef, isFocused, isInvalid, name, onChange, value) + the field-specific props below.
| Prop | Type | Default | Description |
|---|---|---|---|
control |
Control<FormData> |
— | Required. The control from useForm. |
name |
FieldPath<FormData> |
— | Required. Field path in the form values. |
rules |
RegisterOptions |
— | Extra react-hook-form rules; merged with the built-in required rule below. |
shouldUnregister |
boolean |
— | Unregister the field (drop its value) on unmount. |
isRequired |
boolean |
false |
Adds a required rule and the required indicator on the label. |
requiredMessage |
string |
localized | Overrides the required rule message. |
onChange |
(value: ComboboxValue<Id>, event) => void |
— | Called after the field value updates. |
onChangeConfirm |
(value) => Promise<boolean> |
— | Async gate: the change is committed only if the returned promise resolves true. |
All visual props (label, options, loadOptions, placeholder, isClearable, size, variant, helperText, renderOption, keyExtractor, iconName, the empty-state messages, leftAddon/rightAddon/leftElement/rightElement, the dropdown* props, …) are forwarded to the twin — see @uxf/ui/combobox.
isRequired adds a required rule; override its message with requiredMessage (default localized "This field is required", key uxf-form-combobox:validation.required).rules; they are merged with the built-in rule.helperText and sets isInvalid.Form — it reads the form context (formId for the default id = ${formId}__${name}, and inherits isDisabled / isReadOnly) and needs a react-hook-form control.loadOptions and options is empty (in addition to the form's isDisabled and the field's own isDisabled).@uxf/ui/combobox, so include that component's stylesheet(s) and the @uxf/ui token layer — see @uxf/ui/combobox.@uxf/ui/combobox