Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Page Reload on Input Blur Instead of Showing Validation Errors In Case of Asynchronous Refinements in Zod Schema #856

Open
madhukarVeefin opened this issue Jan 31, 2025 · 1 comment

Comments

@madhukarVeefin
Copy link

madhukarVeefin commented Jan 31, 2025

Describe the Bug and the Expected Behavior

Description

When using @conform-to/zod with async: true, the form reloads on each blur event instead of displaying validation errors inline. This happens even when using shouldValidate: "onBlur" in useForm.

Environment

  • @conform-to/react: ^1.1.5
  • @conform-to/zod: ^1.1.5
  • React version: ^18.3.1
  • Zod version: ^3.23.8
  • Browser: Chrome
  • Package Manager: pnpm

Conform Version

v1.1.5

Steps to Reproduce the Bug or Issue

1. Define an Async Zod Schema with superRefine

import { z } from "zod";

// Function to create the final schema with required fields
const createSchema = (formData: FormData) => {
  const schemaFields: Record<string, any> = {};
  if (formData.has("companyName")) {
    schemaFields.companyName = z
      .string({ required_error: "Company name is Required" })
      .trim()
      .min(1, "Company name cannot be empty")
      .superRefine(async (value, ctx) => {
        try {
          const result = await someAsyncValidation(value);
          if (!result) {
            ctx.addIssue({
              code: z.ZodIssueCode.custom,
              message: "Async validation failed",
            });
          }
        } catch (error) {
          ctx.addIssue({
            code: z.ZodIssueCode.custom,
            message: `Validation error: ${error.message}`,
          });
        }
      });
  }
  return z.object(schemaFields);
};

export const companySchema = async (formData: FormData) => {
  return await parseWithZod(formData, {
    schema: createSchema(formData),
    async: true
  });
};

2. Use useForm with onValidate and async: true

import { useForm } from "@conform-to/react";
import { Form } from "@remix-run/react";
import { companySchema } from "./schema";

const [form, fields] = useForm({
  shouldValidate: "onBlur",
  async onValidate({ formData }) {
    return await companySchema(formData);
  },
});

return (
  <Form method="post" id={form.id} onSubmit={form.onSubmit} noValidate>
    <input {...fields.companyName} />
    <input {...fields.server} />
    <button type="submit">Submit</button>
  </Form>
);

3. Expected Behavior

  • On blur, the corresponding field should show validation errors if invalid.
  • No page reload should happen.

4. Observed Behavior

  • The entire page reloads when the user blurs an input field.
  • Instead of individual field validation, all errors appear at once after the reload.
  • Removing async: true prevents the reload but breaks async validation.

Important

I am getting this error in the browser console:

chunk-DATYQ7L7.js:3750 Uncaught TypeError: submission.reply is not a function

Tried multiple solutions as per the documentation, but nothing worked.

What Browsers Are You Seeing the Problem On?

  • Chrome

Screenshots or Videos

Image

Additional Context

Findings & Possible Causes

  • Setting async: true seems to be causing a full form submission instead of handling validation inline.
  • superRefine might be interfering with Conform’s async validation mechanism.
  • It is possible that Conform expects validation results synchronously, even when using async: true.
  • The form submission might be triggered because Conform cannot properly handle async validation on blur.
@updbqn
Copy link

updbqn commented Mar 4, 2025

From my understanding conform doesn't support async validation on the client. So the fallback on server validation is working as intended.

Take a look at Conform / Async Validation for one possible approach.

Another approach is to always keep schema sync and do something like:

// server
if (submission.status !== "success") {
  return submission.reply();
}

const isValidAsync = await validateAsync(submission.value);

if (!isValidAsync) {
  return submission.reply({
    fieldErrors: {
      companyName: ["This company name is already used"],
    },
  });
}

Though in both cases the async validations will only run on submit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants