edmundhung / conform

A type-safe form validation library utilizing web fundamentals to progressively enhance HTML Forms with full support for server frameworks like Remix and Next.js.
https://conform.guide
MIT License
1.87k stars 101 forks source link

Input field no longer accepts changes after validation #202

Open lauritzsh opened 1 year ago

lauritzsh commented 1 year ago

I have an issue where when a specific field gets validated and is invalid, then it is no longer possible to write a value. However, it specifically happens for a 3rd party library and I'm unsure where exactly to file this issue. Apologize if the issue does not belong to Conform but React Aria.

I wrote a simple application to showcase it: https://stackblitz.com/edit/stackblitz-starters-8jstfy?file=src%2FApp.tsx. To reproduce, hit the submit on each form and try to update the value in the inputs. You'll notice the top does not work, but the bottom one does. The only difference is the top has an attribute name="hello". Also notice this works fine in Firefox, but affects Chromium and Safari.

What's weird is if you inspect the first input element and remove the data-conform-touched="true" attribute then it works fine again. This is what led me to believe it has something to do with Conform, but I'm not sure how to figure out what's happening.

edmundhung commented 1 year ago

Thanks for the stackblitz, @lauritzsh!

This is interesting. If you change the shouldRevalidate to onBlur, the issue seems to be gone. This might be related to the revalidation mechanism which creates a temporary button and trigger a form submit with it and somehow stopped the custom input from updating the value. Does it happen with any other inputs from react-aria-component?

lauritzsh commented 1 year ago

Thanks for quick reply! So far in my project I've only experienced this with NumberField, but I just went through and tried some other components, those that I deemed relevant. I updated the StackBlitz to more components and made it more realistic with the {...input} prop spread: https://stackblitz.com/edit/stackblitz-starters-3xdnbe?file=src%2FApp.tsx

Since it doesn't happen consistently with every component but only NumberField, SearchField and ComboBox I kind of suspect the bug lies with React Aria. Let me know if there's nothing to do and I should open an issue in their repo 🙏

edmundhung commented 1 year ago

I am still trying to pinpoint the actual issue. Somehow I can reproduce a similar issue when using just Remix with the NumberField from react-aria-components:

import { useSubmit } from '@remix-run/react';
import { NumberField, Label, Input } from 'react-aria-components';

export default function Example() {
    const submit = useSubmit();

    return (
        <form
            method="get"
            onInputCapture={(event) => {
                // Submit the form as user types
                event.currentTarget.requestSubmit();
            }}
            onSubmit={event => {
                event.preventDefault();

                // Comment out next line and the input will works as expected
                submit(event.currentTarget);
            }}
        >
            <NumberField>
                <label>Number Field</label>
                <Input name="test" />
            </NumberField>
        </form>
    );
}
edmundhung commented 1 year ago

Here is a codesandbox that reproduce the issue with just react.

I notice two things:

  1. If we trigger form submit on onInput instead of onInputCapture, the issue is gone.
  2. If we don't call setState on onSubmit, the issue is gone too.

We probably should open an issue for the react-aria team.

lauritzsh commented 1 year ago

Apologize for not getting back to you sooner! Impressive detective work. I have submitted an issue. Feel free to close this if you wish, as it seems to have nothing to do with Conform.

musjj commented 2 weeks ago

It looks like the issue is due to the component being controlled:

I finally got a chance to look at this a little.

I don't think this is our issue. This won't work with any controlled input. See https://codesandbox.io/s/react-aria-components-number-not-updated-forked-69v5kq?file=/src/App.js with no code from us.

Controlling components is extremely common and I'm willing to be most design system implementations control their components even if you can use them in a controlled or uncontrolled way.

On a different note, our Input should not be used standalone. It should be used inside of our other high level components. If you put it inside a TextField, then it will exhibit the same behavior.

Is there a way to solve this with Conform?