Skip to content

feat: defaultSubmitHandler, submitRawValues, resetOnSuccess and 5 issue fixes - #186

Merged
AlemTuzlak merged 2 commits into
mainfrom
feat/issue-sweep
Oct 2, 2026
Merged

AlemTuzlak merged 2 commits into
mainfrom
feat/issue-sweep

Conversation

@AlemTuzlak

Copy link
Copy Markdown
Contributor

This PR adds three opt-in submit features to useRemixForm and fixes five reported bugs. The changeset is minor, so the merge makes the Release PR for 7.3.0.

Description

Features

  • defaultSubmitHandler on the hook return is the handler that runs when submitHandlers.onValid is not set. A custom onValid can do its own work and then call it. The form action, method and encType of the last handleSubmit call still apply, so you do not have to pass them through.
  • submitRawValues: true makes the default handler send getValues() instead of the resolver output. A zod .transform() then runs only on the server.
  • resetOnSuccess: true resets the form when the submission ends and the action returned no errors.

Fixes

Closes #185
Closes #178
Closes #175
Closes #139
Closes #148
Closes #172
Closes #157

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

  • Unit tests

Checklist:

  • My code follows the guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings or errors
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

The new options have JSDoc, but the README does not describe them yet. ESLint does not run in this repo (ESLint 9 finds no flat config), so the "no new warnings" box is not ticked.

Testing

Commands run

  1. npx vitest run: 66 passed. The new tests for Field method in values causes form to fail submission #139, Expose default submit handler #148, Automatically reset form on valid submission / loader revalidation #157, Incorrect serialization of zod objects with complex types (transform, refine,...) #172, Form submission triggers client-side navigation when basename is set #175 and Arrays of files or FileList objects with only one element in them are not parsed as arrays #178 failed before the change. The Cannot clear custom errors when returned by the server #12 test passed before the change.
  2. npx tsc --noEmit and npx prettier src --check: clean.
  3. npm run build: success.
  4. Type error on <RemixFormProvider {...form}> with react-hook-form >= 7.86: missing getErrors, resetDefaultValues #185 check against the built .d.ts. I built main and this branch with react-hook-form 7.75, as CI does. Then I installed 7.89 (--no-save) and type-checked a consumer file. The main build fails with Property 'getErrors' does not exist and missing ... getErrors, resetDefaultValues. This branch compiles with no errors.
  5. npx vitest run with react-hook-form 7.89 installed: 66 passed.

Manual test

  1. Install react-hook-form 7.89 in an app, and use <RemixFormProvider {...useRemixForm(...)}>. With 7.2.1 you get TS2739. With this branch it compiles.
  2. Add <input name="method" /> to a form that uses handleSubmit. With 7.2.1 the submit throws toLowerCase is not a function (or replace is not a function for action). With this branch it submits.
  3. Set basename: "/app/" on the router, and submit a form. With 7.2.1 the app navigates on the client. With this branch the action runs.
  4. Submit a form with one file in a multiple file input, and call parseFormData in the action. You now get an array with one File.

How this PR makes testing easy

Each issue has its own test in src/hook/index.test.tsx or src/utilities/index.test.ts, with the issue number in the test name.

Risk / rollback

  • UseRemixFormReturn["handleSubmit"] now has only the event signature. Before, the type also allowed the react-hook-form signature handleSubmit(onValid), which did not work at runtime.
  • On the server, the single-file entry now has the key files[] and not files. If an action reads formData.get("files") directly instead of with parseFormData, it does not find one file. With two or more files, nothing changes.
  • All three features are opt-in. To undo, revert this PR before the Release PR is merged.

Public API change

Before

// #148: no way to call the default submit after custom work
// #172: the client sends the zod output, then the server transforms again
// #157: reset manually
useEffect(() => form.reset(), [actionData]);

After

// #148 + #157
const form = useRemixForm<Values>({
  resolver,
  resetOnSuccess: true,
  submitHandlers: {
    onValid: async (data) => {
      const token = await getThirdPartyToken();
      form.defaultSubmitHandler({ ...data, token });
    },
  },
});

// #172: the server gets "2025-01-01", not the transformed value
const dateForm = useRemixForm<Values>({ resolver, submitRawValues: true });

Note: with submitRawValues: true, defaultSubmitHandler sends getValues() and ignores the data that it gets. So do not combine it with the #148 pattern above.

createFormData sent each file of a FileList or file array under the
plain key. With one file there is only one entry, so generateFormData
parsed it as a single File and not as [File].

A single file now gets a "[]" key. A key that already ends with "[]"
does not get a second suffix.

Closes #178
Features:
- defaultSubmitHandler on the hook return. A custom onValid can call it
  to submit in the default way. The form action, method and encType of
  the last handleSubmit call still apply (#148).
- submitRawValues option: the default submit handler sends getValues()
  and not the resolver output (#172).
- resetOnSuccess option: reset the form after a submission when the
  action returns no errors (#157).

Fixes:
- Derive the return types of useRemixForm and useRemixFormContext from
  UseFormReturn. The built .d.ts listed the members of react-hook-form
  7.75, so getErrors and resetDefaultValues were missing for users of
  newer versions (#185).
- Read action, method and enctype with the HTMLFormElement getters. An
  input with one of these names replaced the form property (#139).
- Remove a trailing slash from the basename before it is removed from
  the action, so the action keeps its leading "/" (#175).
- Add a regression test that clearErrors removes server errors (#12).
@pkg-pr-new

pkg-pr-new Bot commented Oct 2, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/remix-hook-form@186

commit: a79961e

@AlemTuzlak
AlemTuzlak merged commit 8232fe6 into main Oct 2, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment