Field Hooks
Complete reference for field hooks — useDataField, useLayoutField, and utilities.
Field Hooks
BuzzForm provides hooks for building custom field components with access to field state, errors, options, and a11y.
Data Field Hook
useDataField
Prop
Type
Aggregates common state for data field components.
Returns:
fieldApi- TanStack field APIfield- Field schemaformData- Current form valueshandleChange/handleBlur- Change handlerslabel,description,placeholder- Resolved text valuesisDisabled,isReadOnly,isRequired,isHidden- State flagsisInvalid,errors,shouldShowErrors- Error stateariaDescribedBy,descriptionId,errorId- Accessibility IDs
Example:
import { useDataField } from "@buildnbuzz/form-react";
import type { TextField as TextFieldDef } from "@buildnbuzz/form-core";
function CustomTextField() {
const {
fieldApi,
field,
handleChange,
handleBlur,
label,
placeholder,
description,
isDisabled,
isReadOnly,
isRequired,
isInvalid,
errors,
ariaDescribedBy,
} = useDataField<TextFieldDef>();
const value = (fieldApi.state.value as string) ?? "";
return (
<div className="space-y-2">
{label && (
<label htmlFor={fieldApi.name}>
{label}
{isRequired && <span>*</span>}
</label>
)}
<input
id={fieldApi.name}
type="text"
value={value}
onChange={(e) => handleChange(e.target.value)}
onBlur={handleBlur}
placeholder={placeholder}
disabled={isDisabled}
readOnly={isReadOnly}
aria-invalid={isInvalid}
aria-describedby={ariaDescribedBy}
/>
{description && <p className="text-sm">{description}</p>}
{isInvalid && errors.length > 0 && (
<p className="text-sm text-red-500">{errors[0]}</p>
)}
</div>
);
}Layout Field Hook
useLayoutField
Prop
Type
Aggregates state for layout field components.
Returns:
field- Field schemaform- TanStack form instancelabel,description- Resolved text valuesisHidden,isDisabled,isConditionMet- State flags- All
FieldContextValueproperties
Example:
import { useLayoutField } from "@buildnbuzz/form-react";
function CustomGroupField({ children }) {
const { field, label, isHidden, isDisabled } = useLayoutField();
if (isHidden) return null;
return (
<fieldset disabled={isDisabled}>
<legend>{label}</legend>
{children}
</fieldset>
);
}Options Hook
useFieldOptions
Prop
Type
Resolve and normalize options for select, radio, checkbox group.
Returns:
options- Normalized options array ({ label, value, disabled, ui }[])isLoading- Alwaysfalse(reserved for future async sources)
Example:
import { useDataField, useFieldOptions } from "@buildnbuzz/form-react";
import type { SelectField as SelectFieldDef } from "@buildnbuzz/form-core";
function CustomSelectField() {
const { fieldApi, handleChange, field } = useDataField<SelectFieldDef>();
const { options } = useFieldOptions(field.options);
return (
<select
value={fieldApi.state.value ?? ""}
onChange={(e) => handleChange(e.target.value)}
>
{options.map((opt) => (
<option key={opt.value} value={opt.value} disabled={opt.disabled}>
{opt.label}
</option>
))}
</select>
);
}Error State Hook
useFieldErrorState
Access field errors and validation state.
Returns:
errors- Array of error messagesisInvalid- Whether field has errorsshouldShowErrors- Whether errors should be displayed
A11y IDs Hook
useFieldA11yIds
Generate accessible IDs for form fields.
Returns:
descriptionId- ID for description elementerrorId- ID for error elementariaDescribedBy- Combined value foraria-describedby
Context Hooks
useFieldContext
Read the field context directly:
import { useFieldContext } from "@buildnbuzz/form-react";
function CustomComponent() {
const { field, form, fieldPath, formData, isHidden } = useFieldContext();
// Access raw context values
}useDataFieldContext
Read data field context with guaranteed fieldApi:
import { useDataFieldContext } from "@buildnbuzz/form-react";
function CustomDataField() {
const { fieldApi, field, fieldPath } = useDataFieldContext();
// fieldApi is guaranteed to exist
}useFormContext
Access the form instance from anywhere in the tree:
import { useFormContext } from "@buildnbuzz/form-react";
function SubmitButton() {
const form = useFormContext();
return (
<button
type="submit"
disabled={!form.state.canSubmit}
>
Submit
</button>
);
}useFieldApi
Convenience hook for just the field API:
import { useFieldApi } from "@buildnbuzz/form-react";
function CustomInput() {
const fieldApi = useFieldApi();
return <input ref={fieldApi?.ref} />;
}Utility Hooks
useNestedErrorCount
Count errors in nested fields (for groups, arrays, tabs):
import { useLayoutField, useNestedErrorCount } from "@buildnbuzz/form-react";
function CustomGroupField({ children }) {
const { field } = useLayoutField();
const errorCount = useNestedErrorCount(field.fields);
return (
<div className="border p-4 rounded">
<div className="flex items-center gap-2 mb-4">
<h3>{field.label}</h3>
{errorCount > 0 && (
<span className="bg-red-500 text-white text-xs px-2 py-1 rounded">
{errorCount} errors
</span>
)}
</div>
{children}
</div>
);
}useResolvedFieldText
Resolve dynamic strings for label, description, placeholder:
import { useDataField, useResolvedFieldText } from "@buildnbuzz/form-react";
function CustomField() {
const { field } = useDataField();
const { label, description, placeholder } = useResolvedFieldText({
label: field.label,
description: field.description,
placeholder: field.placeholder,
});
return (
<>
<label>{label}</label>
<input placeholder={placeholder} />
{description && <p>{description}</p>}
</>
);
}Hook Usage Summary
| Hook | Use Case |
|---|---|
useDataField | Custom data field components |
useLayoutField | Custom layout container components |
useFieldOptions | Select, radio, checkbox group with options |
useFieldErrorState | Access errors and validation state |
useFieldA11yIds | Generate accessible IDs |
useFieldContext | Raw field context access |
useDataFieldContext | Data field context with guaranteed fieldApi |
useFormContext | Access form instance |
useFieldApi | Just the field API |
useNestedErrorCount | Count errors in nested fields |
useResolvedFieldText | Resolve dynamic strings |
Out-of-Context Errors
Using hooks outside their required context throws:
useFieldContext must be used within a BuzzForm <Field> or <LayoutField> componentuseDataFieldContext must be used within a BuzzForm data fieldWrap your component with <Field> or <LayoutField> first.