T
TanStack3mo ago
genetic-orange

Correct validation/error display on both field and form components

I'm curious what everyone's using. I love tanstack form but I feel it's difficult to achieve good defaults on the form and field validation - using zod v4 for useAppForm.validators. What I have right now:
export function FormErrors({
meta,
}: {
meta: FieldMeta<any, any ...>
>;
}) {
return (
meta.isDirty &&
meta.errors.length > 0 && (
<em className="text-destructive text-sm">
{meta.errors.map((err) => err.message).join(", ")}
</em>
)
);
}

export function SubmitButton({
label,
isLoading,
}: {
label: string;
isLoading?: boolean;
}) {
const form = useFormContext();

return (
<form.Subscribe selector={(state) => [state.isSubmitting, state.isValid]}>
{([isSubmitting, isValid]) => (
<Button
type="submit"
className="w-full bg-indigo-600 py-2 px-4 text-white rounded-md shadow hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 transition-colors"
disabled={!isValid || isSubmitting}
>
{isLoading ? <Loader2 className="animate-spin" /> : label}
</Button>
)}
</form.Subscribe>
);
}
export function FormErrors({
meta,
}: {
meta: FieldMeta<any, any ...>
>;
}) {
return (
meta.isDirty &&
meta.errors.length > 0 && (
<em className="text-destructive text-sm">
{meta.errors.map((err) => err.message).join(", ")}
</em>
)
);
}

export function SubmitButton({
label,
isLoading,
}: {
label: string;
isLoading?: boolean;
}) {
const form = useFormContext();

return (
<form.Subscribe selector={(state) => [state.isSubmitting, state.isValid]}>
{([isSubmitting, isValid]) => (
<Button
type="submit"
className="w-full bg-indigo-600 py-2 px-4 text-white rounded-md shadow hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 transition-colors"
disabled={!isValid || isSubmitting}
>
{isLoading ? <Loader2 className="animate-spin" /> : label}
</Button>
)}
</form.Subscribe>
);
}
This is mostly OK -- but the error is too eager (when user starts typing an email in a field, it will show the error until the put @.com, and the submit button shows as valid when the form is first loaded without anything is typed, then gets invalidated as user types. I'd like to achieve a configuration that: 1. Displays errors on a field only if it's dirty AND user is no longer on it 2. Submit button should be invalid on first load
3 Replies
environmental-rose
environmental-rose3mo ago
if you attach the onBlur event handler field.handleBlur, you can utilize the meta.isBlurred property to display errors as for the submit button, give isPristine a try. It‘s true until a user changes a field @winston.p
genetic-orange
genetic-orangeOP3mo ago
ah isPristine works. How do I attach the isBlurred? If I do a plain isBlurred as one of the && conditions, it doesn't show any error even after user leaves the field
environmental-rose
environmental-rose3mo ago
your UI component should have some form of onBlur={() => {}} pass field.handleBlur in there

Did you find this page helpful?