UNPKG

@payfit/unity-components

Version:

103 lines (85 loc) 2.99 kB
# Unity TanStack Form patterns ### Composed API (default) Drop a single bound field component inside `<form.AppField>`. It bundles label, input, helper text, feedback, and a11y wiring. ```tsx <form.AppField name="firstName"> {field => ( <field.TextField label="First name" helperText="As it appears on your ID" isRequired /> )} </form.AppField> <form.AppField name="country"> {field => ( <field.SelectField label="Country" options={[ { value: 'fr', label: 'France' }, { value: 'es', label: 'Spain' }, ]} /> )} </form.AppField> ``` ### Atomic API (only when customizing layout/parts) Reach for Atomic when you need to interleave custom content between the label and the input, or swap an input for a non-standard control. Wraps every part in `field.Field`. ```tsx <form.AppField name="password"> {field => ( <field.Field> <field.FieldLabel isRequired>Password</field.FieldLabel> <field.FieldHelperText>Enter a strong password</field.FieldHelperText> <field.TextInput type="password" /> <form.Subscribe selector={s => s.values.password}> {password => ( <Text variant="bodySmallStrong">Length: {password.length}</Text> )} </form.Subscribe> <field.FieldFeedbackText /> </field.Field> )} </form.AppField> ``` ### Validation timing `validators.onBlur` is the default; use `onChange` only for fields that need live feedback (password strength meter, search-as-you-type). `fieldRevalidateLogic` gives "blur until first error, then change" UX without polluting form-level validators. ```tsx import { fieldRevalidateLogic, useTanstackUnityForm } from '@payfit/unity-components' const form = useTanstackUnityForm({ defaultValues: { email: '', password: '' }, validators: { onBlur: z.object({ email: z.email() }) }, validationLogic: fieldRevalidateLogic({ whenPristine: 'blur', whenDirty: 'change', fields: ['password'], }), }) <form.AppField name="password" validators={{ onDynamic: ({ value }) => value.length < 8 ? 'Password too short' : undefined, }} > {field => <field.PasswordField label="Password" />} </form.AppField> ``` For fields listed in `fieldRevalidateLogic.fields`, use `onDynamic`/`onDynamicAsync` as the sole validator and omit those fields from the form-level schema; combining both leaves stale errors. ### Optimal subscription with form.Subscribe + selector Pass a `selector` to `form.Subscribe` so it observes only the state needed by its children. A bare subscription re-renders on every form update. ```tsx <form.Subscribe selector={s => s.values.password}> {password => <Text>Length: {password.length}</Text>} </form.Subscribe> <form.Subscribe selector={s => [s.canSubmit, s.isSubmitting] as const}> {([canSubmit, isSubmitting]) => ( <Button type="submit" isDisabled={!canSubmit} isLoading={isSubmitting}> Submit </Button> )} </form.Subscribe> ```