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

feat: allow SmartInput and Field to receive autoComplete prop #53

Open
janhesters opened this issue Jul 11, 2022 · 2 comments
Open

feat: allow SmartInput and Field to receive autoComplete prop #53

janhesters opened this issue Jul 11, 2022 · 2 comments
Labels
enhancement New feature or request

Comments

@janhesters
Copy link

janhesters commented Jul 11, 2022

Feature request

Current Behavior

Right now, there is no way to give a Field or a SmartInput an autoComplete prop, e.g. autoComplete="username".

Let's say you have a custom Input configured and a Zod schema like this:

import { forwardRef } from 'react';
import type { FormProps } from 'remix-forms';
import { Form as RemixForm } from 'remix-forms';
import type { SomeZodObject } from 'zod';
import { z } from 'zod';

const Input = forwardRef<HTMLInputElement, JSX.IntrinsicElements['input']>(
  ({ type = 'text', ...props }, reference) => (
    <input
      className="shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md"
      ref={reference}
      type={type}
      {...props}
    />
  ),
);

const Form = <Schema extends SomeZodObject>(props: FormProps<Schema>) => (
  <RemixForm<Schema>
    className="space-y-8 divide-y divide-gray-200"
    inputComponent={Input}
    {...props}
  />
);

const schema = z.object({
  firstName: z.string().min(1),
  email: z.string().min(1).email(),
})

And you want to have an input with an autoComplete property, you have to render it like this:

<Field className="sm:col-span-3" name="firstName">
  {({ Label, Errors }) => (
    <>
      <Label>First name</Label>

      <Input
        {...register('firstName')}
        autoComplete="given-name"
      />

      <Errors />
    </>
  )}
</Field>

<Field className="sm:col-span-3" name="emailAddress">
  {({ Label, Errors }) => (
    <>
      <Label>Email address</Label>

      <Input
        {...register('emailAddress')}
        autoComplete="email"
      />

      <Errors />
    </>
  )}
</Field>

This renders using SmartInput as well as configuring inputComponent on the Form useless in these cases.

Desired Behavior

Ideally, we could give the Field or the SmartInput the autoComplete property, so we could render:

<Field className="sm:col-span-3" name="firstName">
  {({ Label, SmartInput, Errors }) => (
    <>
      <Label>First name</Label>

      <SmartInput autoComplete="given-name" />

      <Errors />
    </>
  )}
</Field>

<Field autoComplete="email" className="sm:col-span-3" name="emailAddress" />

(Note that in this case, we could also render firstName straight up as a Field, but I wanted to show the "Custom Field, standard components" version, too.)

We also have to consider this for the Form's renderField prop, e.g.:

renderField={({ Field, autoComplete, ...props }) => {
  const { name } = props;

  return (
    <Field key={name as string} {...props}>
      {({ Label, SmartInput, Errors }) => (
        <>
          <Label />

          <div className="mt-1">
            <SmartInput autoComplete={autoComplete} />
          </div>

          <Errors />
        </>
      )}
    </Field>
  );
}}

Alternatives

Alternatively, maybe there is a way to infer the autoComplete prop from the schema for certain all the keys that are possible autoComplete values.

@danielweinmann
Copy link
Contributor

danielweinmann commented Apr 18, 2023

@janhesters, thank you also for offering to create a PR for this one. I will share what I'd do if I were to implement it at a high level, but please bring as many follow-on questions as you need:

First, I'd create three examples on our test-examples folder. The first one would include a few Fields receiving different autoComplete props each, but without Field receiving children.

The second would include similar Field's receiving the autoComplete prop, but they would all receive children and render inputs like Input, SmartInput, etc. This will make sure that Field passes its own autoComplete prop along to inputs when the inputs don't receive it directly.

The third would do the same with SmartInputs receiving the autoComplete prop directly.

Then I'd write failing E2E tests, allowing me to TDD my way to implementation.

Only then I'd start implementation. For the Field, I'd add the autoComplete prop here, destructure it here, and then pass it to all appropriate inputs inside this long if/else mapping, which is used for when Field receives children.

For the SmartInput, I'd first add the prop here and then make sure it receives the one passed to Field here, which is used for when Field does not receive children.

Then I'd destructure it here and pass it to the appropriate inputs inside this chain of ternaries.

I probably missed something, and I hope I didn't take away the fun by giving you the (probably) precise places to change. But I know this code is complex, and I thought this would be an incentive for a good first PR :D

Let me know if you have any doubts!

@janhesters
Copy link
Author

Wow thanks a ton! I'm going to finish a PR over the coming days. Just worked on it for an hour, but its much to learn in this codebase haha.

I hope I didn't take away the fun by giving you the (probably) precise places to change.

No, you honestly enable me be able to write the PR in the first place! Thanks again, will post here when the PR is ready again, or if I have more questions 🙏

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

No branches or pull requests

3 participants