Components
Form Field
A smart form field wrapper with built-in label, hint, error, and react-hook-form integration. Pass a `name` prop inside a FormProvider to auto-resolve errors — or use manual props for full control.
Installation
bunx @happlyui/cli@latest add form-field
Dependencies
npm packages
react-hook-form
Registry dependencies
These are automatically installed when you add this component.
happly-ui-utilsform-field-contextuse-form-field-bindinglabelhint
Usage
import * as FormField from "@/components/ui/form-field"
// Automatic mode (with FormProvider)
<FormField.Root name="email" label="Email Address" required hint="This is a hint text.">
<Input.Composed placeholder="hello@example.com" {...register('email')} />
</FormField.Root>
// Manual mode (without FormProvider)
<FormField.Root label="Email Address" error={error} hint="This is a hint text.">
<Input.Composed placeholder="hello@example.com" />
</FormField.Root>
Examples
Demo
Props-driven form fields with label, hint, and various input types.
<FormField.Root
label="Email Address"
htmlFor="email"
required
labelSub="(Required)"
labelInfo="We'll use this to contact you."
hint="This is a hint text to help user."
>
<Input.Composed id="email" leadingIcon={RiMailLine} placeholder="hello@example.com" />
</FormField.Root>
With Error
Form field with error state. Error replaces hint and auto-sets hasError.
<FormField.Root
label="Email Address"
htmlFor="email"
required
hint="This is a hint text."
error="Please enter a valid email address."
>
<Input.Composed id="email" leadingIcon={RiMailLine} />
</FormField.Root>
Disabled
Disabled form field. Disabled state auto-flows to children, label, and hint.
<FormField.Root
label="Email Address"
htmlFor="email"
required
hint="This is a hint text."
disabled
>
<Input.Composed id="email" leadingIcon={RiMailLine} />
</FormField.Root>
Compound Mode
Full control using sub-components. FormField.Label and FormField.Hint auto-read hasError/disabled from context.
<FormField.Root htmlFor="email" hasError>
<FormField.Label required sub="(Required)">
Email Address
</FormField.Label>
<Input.Root hasError>
<Input.Wrapper>
<Input.Icon as={RiMailLine} />
<Input.Input id="email" placeholder="hello@example.com" />
</Input.Wrapper>
</Input.Root>
<FormField.Error>Please enter a valid email address.</FormField.Error>
</FormField.Root>
Form Validation
Complete sign-up form with automatic react-hook-form integration. Wrap with FormProvider and pass `name` — errors, hasError, disabled, and id are resolved automatically.
const methods = useForm({ resolver: zodResolver(schema), mode: 'onTouched' });
<FormProvider {...methods}>
<form onSubmit={methods.handleSubmit(onSubmit)}>
<FormField.Root name="email" label="Email" required>
<Input.Composed
leadingIcon={RiMailLine}
placeholder="hello@example.com"
{...methods.register('email')}
/>
</FormField.Root>
</form>
</FormProvider>
API Reference
FormField.Root
The root form field container. Auto-resolves errors from react-hook-form when `name` is provided inside a FormProvider. Auto-injects `hasError`, `disabled`, and `id` into direct children.
| Prop | Type | Default | Description |
|---|---|---|---|
name | string | - | Field name for react-hook-form integration. When inside a FormProvider, auto-reads errors from form state. Also used as the default `htmlFor`/`id`. |
label | React.ReactNode | - | Label text. When provided, renders a composed Label automatically. |
htmlFor | string | - | Links label to input via htmlFor/id. Defaults to `name` when not provided. |
required | boolean | false | Show asterisk on the label |
labelSub | React.ReactNode | - | Sub-text rendered after the label (e.g. '(Optional)') |
labelInfo | React.ReactNode | - | Info tooltip content rendered as Label.Info |
hint | React.ReactNode | - | Hint text rendered below children. Hidden when error is present. |
error | React.ReactNode | - | Error message. Overrides auto-resolved RHF error when provided. |
hasError | boolean | false | Error state. Auto-set when error is present (manual or RHF-resolved). |
disabled | boolean | false | Disabled state. Auto-injected into direct children, label, and hint. |
className | string | - | Additional className to override or extend styling |
FormField.Label
Composed label that auto-reads disabled and htmlFor from FormField context.
| Prop | Type | Default | Description |
|---|---|---|---|
required | boolean | false | Show asterisk |
sub | React.ReactNode | - | Sub-text after label |
info | React.ReactNode | - | Info tooltip content |
FormField.Hint
Composed hint that auto-reads hasError and disabled from FormField context.
| Prop | Type | Default | Description |
|---|---|---|---|
icon | React.ElementType | - | Custom icon component. Defaults to built-in info circle. |
FormField.Error
Error message display with error styling. Returns null when children is falsy.
| Prop | Type | Default | Description |
|---|
useFormField
Hook to access FormField context (hasError, disabled, id, name) from custom child components.
| Prop | Type | Default | Description |
|---|