Components
TextField
The form-bound text input. It composes the controlled <Input> primitive and reads its field from TanStack Form context — so you never wire handleChange, invalid, or aria-describedby by hand. It maps touched + errors to the solid error styling and an error HelperText (icon and all, so the error never leans on color alone), and links label ↔ control ↔ description for you. Ships from the form layer, used inside useHaloForm.
How it works
Render it inside an form.AppField (or via the bound field.TextField). It reads the field through context — name, value, blur, errors — and owns the meta→props mapping once:
- touched + errors →
invalid(error styling, aria-invalid) and the error message in aHelperText. - showValid + touched + no error →
valid(the friendly "looks good" state). - label ↔ input ↔ helper/error wired with
aria-describedbyand a generated id. - Every other
Inputprop —placeholder,type, leading / trailing icons — passes straight through.
Live demo
A one-field form. Type one character and watch the error show up; two or more clears it; hit submit to see the value. The styling, the helper→error swap, and the ARIA are all the field's doing.
Props
- label: ReactNode
- The field’s label — rendered as a real <label>, associated to the input for a11y. Required.
- helperText?: ReactNode
- A neutral hint shown below the field when there’s no error. The error message replaces it when the field is invalid.
- showValid?: boolean
- Opt in to the success state once the field is touched and passes — the friendly "looks good" signal.
- placeholder, type, leadingIcon, …
- Every
Inputprop except the bound ones (value, onChange, onBlur, invalid, valid, name, id, aria-describedby) passes through — soplaceholder, the icon slots, and the native types all work.
Usage
import { Form, useHaloForm, TextField, SubmitButton, z } from '@halo-compliance/ui'
const schema = z.object({ org: z.string().min(2) })
function CreateOrg() {
const form = useHaloForm({
defaultValues: { org: '' },
validators: { onChange: schema },
})
return (
<Form form={form}>
<form.AppField name="org">
{() => <TextField label="Organization name" placeholder="Acme Lending Co." />}
</form.AppField>
<form.AppForm><SubmitButton>Create</SubmitButton></form.AppForm>
</Form>
)
}<form.AppField name="email">
{() => (
<TextField
label="Work email"
type="email"
helperText="We only use this for compliance alerts."
showValid
/>
)}
</form.AppField>Related
- /input — the primitive TextField composes (states, icon slots, the works).
- /form — the form layer: useHaloForm, Form, SubmitButton, FormError.
- /textarea — the multi-line sibling and its TextAreaField.
- /helper-text — the helper / error message pattern TextField renders.