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

Overriding fields #226

Open
joaomilho opened this issue Sep 20, 2023 · 2 comments
Open

Overriding fields #226

joaomilho opened this issue Sep 20, 2023 · 2 comments

Comments

@joaomilho
Copy link

So remix-forms allows overriding fields in a number of ways, but its API is still crusty if one wants to integrate a different UI library with it. Let's focus on the example of using NextUI: In NextUI the Input component expects the label as prop. In this case remix-forms allows the following overrides:

// overriding inside the form
<Form schema={schema} >
    {({ Field, Errors, Button, register }) => (
      <Field name="email">
        {({ Errors }) => (
            <>
            <Input {...register("email")} label="Email" />
            <Errors />
          </>
        )}
      </Field>
 )}
</Form>

This works fine, but it's tedious when all the fields have to be overridden in all forms. Now, one can also override the input component:

<Form schema={schema} inputComponent={InputComponent} />
  
const InputComponent = React.forwardRef<HTMLInputElement, JSX.IntrinsicElements["input"]>((props, ref) => {
  return (
      <Input {...props} label={props.???} />
  );
});

Turns out that because remix-forms assumes the label is a different react component, not just a string, the label is not passed down to the custom input component. Needless to say, overriding the Label component is useless, which leaves us with overriding the Field component.

<Form schema={schema} fieldComponent={FieldComponent} />
  
const FieldComponent = ((props: JSX.IntrinsicElements['div']) => {
  // props.children[0] is a label component
  return (
      <div {...props}>???</div>
  );
});

Now the issue is that the label is a component passed down to the custom field component as children, so accessing its props is a clumsy thing to do.

Maybe I'm missing something, but it would be nice to have a simpler way to override a full component, with plain (no components) props.

@danielweinmann
Copy link
Contributor

Yeah, component libs that do not match 1:1 the HTML tags in their components are trickier to integrate. That said, some people managed to do a decent job using renderField + useField + useFormState. Personally, I'd advise using Remix Forms with libs that have a 1:1 correlation with HTML, otherwise it might be too cumbersome.

At least until we devise a more flexible API :) we're very open to ideas! I'll leave this issue open for that reason.

@mbrowne
Copy link

mbrowne commented Feb 1, 2024

I was able to solve this particular case using useField:

const FormInputField = React.forwardRef<HTMLInputElement, InputProps>(
    (props, ref) => {
        const { label } = useField()
        return (
            <Input
                ref={ref}
                {...props}
                label={label}
            />
        )
    }
)
FormInputField.displayName = 'FormInputField'

const EmptyComponent = () => null

export function MyForm() {
    return (
        <Form
            schema={schema}
            labelComponent={EmptyComponent}
            inputComponent={FormInputField}
        >
          <Field name="firstName" label="First name" />

If desired, you can also use useField for custom rendering of error messages by passing errorComponent={EmptyComponent} as well.

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

3 participants