react-hook-form-bound form fields for UXF projects, plus the Form container that wires them up. Each field wraps its @uxf/ui primitive and is a subpath import — e.g. import { TextInput } from "@uxf/form/text-input" — with its own README under packages/form/<component>/.
Note: This package uses translations — an ancestor must provide
TranslationsProvider(@uxf/core-react/translations).UiContextProviderfrom@uxf/ui/contextalready includes it; see the@uxf/uisetup.
Use @uxf/form to build forms backed by react-hook-form: wrap fields in a Form and bind each via control/name. Each field derives its value, validation error (helperText + isInvalid), and disabled/read-only state from the form. For a standalone, manually-controlled input outside a form, use the matching @uxf/ui component directly.
yarn add @uxf/formPeer dependencies: @uxf/core, @uxf/core-react, @uxf/styles, @uxf/ui, react-hook-form, dayjs, react, react-dom.
Fields render @uxf/ui components, so also complete the @uxf/ui setup — the UiContextProvider and the component/token CSS.
import { Form } from "@uxf/form/form";
import { TextInput } from "@uxf/form/text-input";
import { useForm } from "react-hook-form";
interface FormData {
email: string;
}
function SignInForm() {
const formApi = useForm<FormData>({ defaultValues: { email: "" } });
return (
<Form formApi={formApi} id="sign-in" onSubmit={(values) => console.log(values)}>
<TextInput control={formApi.control} isRequired label="E-mail" name="email" type="email" />
</Form>
);
}
Every field must be rendered inside a <Form> — it provides the react-hook-form context plus the form id and disabled/read-only state that fields inherit.
Each component has its own README under packages/form/<component>/. Fields pair with a @uxf/ui twin: the @uxf/form field adds react-hook-form wiring and validation, the twin provides the visuals.
Infrastructure
form — the <Form> container (react-hook-form FormProvider + <form> + form context).form-renderer — schema/config-driven form rendering.Fields: text-input, textarea, number-input, password-input, money-input, gps-input, checkbox-input, checkbox-button, checkbox-list, radio-group, color-radio-group, toggle, select, combobox, multi-select, multi-combobox, date-picker-input, date-range-picker-input, datetime-picker-input, time-picker-input, file-input, avatar-file-input, dropzone.
useScrollToFirstInvalidFieldReturns a callback that scrolls the first invalid form field into view. It targets the .uxf-form-component.is-invalid element rendered by this package's inputs, so consumers no longer have to reach into internal markup.
import { useScrollToFirstInvalidField } from "@uxf/form/hooks/use-scroll-to-first-invalid-field";
const scrollToFirstInvalidField = useScrollToFirstInvalidField();
// default options: { behavior: "smooth", block: "center" }
scrollToFirstInvalidField();
// override ScrollIntoViewOptions
scrollToFirstInvalidField({ behavior: "auto", block: "start" });
The scroll is deferred internally so it runs after React commits the validation classes. Call it right after mapping errors onto the form — e.g. when a mutation returns server-side validation errors:
.catch((error) => {
ErrorService.handleFormError(error, formApi.setError);
scrollToFirstInvalidField();
});
Calling it again replaces the pending scroll, and unmounting the component cancels it. It is a no-op when no invalid field is present.